//
// You should have received a copy of the GNU General Public License
// along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
-
+
/*jslint laxbreak:true */
/**
* Permet d'executer des commandes tapées par l'utilisateur.
* les commandes sont entrées directement dans la ligne de saisie du message sous la forme :
* /<commande> <paramètres>
- *
+ *
* Voici les commandes supportées :
* /nick <nouveau nick>
* Modifie le nick courant
this.pageMinichat = pageMinichat;
this.util = util;
this.formater = formater;
-
+
// construction du texte d'aide (liste des commandes) de manière statique
this.texteAide = "<div id=\"aideCommandes\"><h1>Commandes</h1><ul>";
objectEach(
description : "Change le nick courant",
usage : "/nick <nouveau nick>",
exec : function(args, client) {
-
+
if (args.length === 0) {
return [euphorik.Commandes.statut.erreur_commande, 'Utilisation de la commande : ' + this.usage];
}
-
+
client.nick = args[0];
$("form#posterMessage input.nick").val(client.nick);
-
+
return [euphorik.Commandes.statut.ok, ''];
}
},
*/
euphorik.Commandes.prototype.exec = function(chaine) {
chaine = chaine.trim();
-
+
var fragments = chaine.split(/\s+/);
if (fragments.length === 0 || fragments[0].charAt(0) != '/') {
return [euphorik.Commandes.statut.pas_une_commande, ''];
}
-
+
var commandName = fragments[0].slice(1);
var args = fragments.slice(1);
-
+
if (commandName === "") {
return [euphorik.Commandes.statut.erreur_commande, 'La commande est vide'];
}
);
return [euphorik.Commandes.statut.ok, ''];
}
-
+
if (euphorik.Commandes.liste.hasOwnProperty(commandName)) {
return euphorik.Commandes.liste[commandName].exec(args, this.client, this.pageMinichat);
}
-
+
return [euphorik.Commandes.statut.erreur_commande, 'La commande /' + commandName + ' est inconnue'];
};
//\r
// You should have received a copy of the GNU General Public License\r
// along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
- \r
+\r
/*jslint laxbreak:true */\r
\r
/**\r
*/\r
euphorik.Conversation = function(conversations, num) {\r
this.conversations = conversations;\r
- \r
+\r
// peut changer au cours de la vie de la conversation, n'est pas un id !\r
this.num = num;\r
- \r
+\r
this.id = Math.floor(Math.random() * 1000000).toString(36);\r
- \r
+\r
this.util = this.conversations.util;\r
this.formater = this.conversations.formater;\r
this.client = this.conversations.client;\r
- \r
+\r
this.idDernierMessageAffiche = 0;\r
this.racine = undefined;\r
- \r
+\r
this.messages = [];\r
this.messagesParId = {};\r
- \r
+\r
this.nbMessageMax = euphorik.conf.nbMessageAffiche; // Le nombre de message affiché par page\r
\r
var messagesXHTML = '<div class="messages"></div>';\r
var messageRacineXHTML = '<div class="messageRacine"></div>';\r
var reverse = this.client.chatOrder === "reverse";\r
- \r
- var XHTML = \r
+\r
+ var XHTML =\r
'<td class="conversation" id="' + this.getId() + '">' +\r
(reverse ? messagesXHTML : "") +\r
'<div class="titre">' +\r
(reverse ? "" : messagesXHTML) +\r
//'<div class="messageReduit" style="height:200px; width:50px"></div>' +\r
'</td>';\r
- \r
+\r
$("#conversations tr").append(XHTML);\r
- \r
+\r
// les infos bulles\r
this.util.infoBulle("Aller à la première page", $("#" + this.getId() + " .titre .numPage"), euphorik.Util.positionBulleType.haut);\r
if (this.num !== 0) {\r
this.util.infoBulle("Créer un lien vers la conversation", $("#" + this.getId() + " .titre .creerLien"));\r
this.util.infoBulle("Close the conversation", $("#" + this.getId() + " .titre .close"));\r
}\r
- \r
+\r
// les différents événements liés à la conversation\r
- var thisConversation = this; \r
+ var thisConversation = this;\r
$("#" + this.getId() + " .titre .creerLien").click(function() {\r
thisConversation.util.replaceSelection(\r
$("form#posterMessage input.message")[0],\r
"{" + thisConversation.client.conversations[thisConversation.num - 1].root.toString(36) + "}"\r
);\r
- }); \r
+ });\r
$("#" + this.getId() + " .titre .close").click(function() {\r
thisConversation.conversations.supprimerConversation(thisConversation.num);\r
});\r
if (!this.racine) {\r
return;\r
}\r
- \r
+\r
if (!(this.racine.id in this.messagesParId)) {\r
this.messagesParId[this.racine.id] = this.racine;\r
var element = $(this.racine.XHTML(true, this.getId()));\r
*/\r
euphorik.Conversation.prototype.setFunPage = function(funNext, funPrev, funReset) {\r
var thisConversation = this;\r
- \r
+\r
$("#" + this.getId() + " .next").click(\r
function() { funNext(thisConversation.num); }\r
);\r
euphorik.Conversation.prototype.ajouterMessage = function(message) {\r
this.messages.push(message);\r
this.messagesParId[message.id] = message;\r
- \r
+\r
// enlève le message exedentaire si nécessaire\r
if (this.messages.length > this.nbMessageMax) {\r
delete this.messagesParId[this.messages.shift().id];\r
}\r
- \r
+\r
// met à jour le membre 'estReponduPar' des messages de la conversation\r
for (var i = 0; i < this.messages.length - 1; i++) {\r
var autreMess = this.messages[i];\r
this.messagesParId = {};\r
this.idDernierMessageAffiche = 0;\r
$("#" + this.getId() + " .messages .message").remove();\r
- \r
+\r
// enlève également la racine\r
$("#" + this.getId() + " .titre .messageRacine").empty();\r
};\r
\r
var messagePair = (this.idDernierMessageAffiche === 0 ? true :\r
($("#" + this.getId() + " .messages div:" + (reverse ? "first" : "last")).attr("class").search("messagePair") === -1)\r
- );
-
- // 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);
- }
- });
+ );\r
+\r
+ // permet d'itérer sur les nouveaux messages à afficher\r
+ var pourChaqueNouveauMessage = function(f) {\r
+ thisConversation.messages.each(function(i, mess) {\r
+ if (mess.id > thisConversation.idDernierMessageAffiche) {\r
+ f(mess);\r
+ }\r
+ });\r
};\r
- \r
+\r
// construction de l'XHTML des messages\r
- var XHTML = "";
+ var XHTML = "";\r
pourChaqueNouveauMessage(function(mess) {\r
XHTML += mess.XHTML(messagePair, thisConversation.getId());\r
messagePair = !messagePair;\r
});\r
- \r
- var DOM = $(XHTML); \r
- \r
+\r
+ var DOM = $(XHTML);\r
+\r
// pour chaque nouveau message au niveau du document on lui assigne ses événements\r
DOM.each(function() { thisConversation.attacherEventsSurMessage(this); });\r
- \r
+\r
if (reverse) {\r
DOM.prependTo("#" + this.getId() + " .messages");\r
} else {\r
DOM.appendTo("#" + this.getId() + " .messages");\r
}\r
- \r
+\r
// enlève les messages exedentaires au niveau du document\r
var nbMessagesAffiche = $("#" + this.getId() + " .messages .message").size();\r
if (nbMessagesAffiche > this.nbMessageMax) {\r
} else {\r
$("#" + this.getId() + " .messages .message").slice(0, nbMessagesAffiche - this.nbMessageMax).remove();\r
}\r
- }
-
- // 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");
- }
- });
- }
+ }\r
+\r
+ // met à jour la classe des messages auquels repondent les nouveaux messages\r
+ // dans le cas où ce message appartient au client courant (c'est un peu de la triche) TODO : ya mieux ?\r
+ pourChaqueNouveauMessage(function(mess) {\r
+ if (mess.auteurId === thisConversation.client.id) {\r
+ objectEach(mess.repondA, function(messId) {\r
+ var mess = thisConversation.messagesParId[messId];\r
+ if (mess) {\r
+ mess.clientARepondu = true;\r
+ $("#conversations #" + mess.getId(thisConversation.getId())).addClass("repondu");\r
+ }\r
+ });\r
+ }\r
});\r
- \r
+\r
if (this.messages.length > 0) {\r
this.idDernierMessageAffiche = this.messages[this.messages.length-1].id;\r
- }
- \r
+ }\r
+\r
// met à jour la racine de la conversation\r
this.majRacine();\r
};\r
euphorik.Conversation.prototype.attacherEventsSurMessage = function(element) {\r
// l'id du message\r
var idMess = this.idMessageFromString($(element).attr("id"));\r
- \r
+\r
if (idMess in this.conversations.messagesRepond) {\r
$(element).addClass("repondEnEvidence");\r
}\r
- \r
+\r
var thisConversation = this;\r
$(".conversationLink", element).click(\r
function(event) {\r
return false;\r
}\r
);\r
- \r
+\r
$(element).click(function(event) {\r
if ($(event.target).is("a") || $(event.target).parents("#outilsBan").length > 0) {\r
return;\r
// les outils de bannissement (uniquement pour les ekMaster)\r
if (thisConversation.client.ekMaster) {\r
$(".nick", element).hover(\r
- function(e) { \r
+ function(e) {\r
var userId = parseInt($(".id", this).text(), 10);\r
var nick = $(this);\r
var h = nick.outerHeight();\r
);\r
}\r
};\r
- \r
+\r
/**\r
* Etablit une liste des messages à mettre en evidence et des messages à cacher.\r
* Puis applique un plan diabolique.\r
* @param id l'id du message\r
*/\r
-euphorik.Conversation.prototype.afficherConversation = function(id) { \r
+euphorik.Conversation.prototype.afficherConversation = function(id) {\r
var thisConversation = this;\r
- \r
+\r
var message = this.messagesParId[id];\r
if (!message) {\r
return;\r
}\r
\r
var mess = message.getConversation(this);\r
- \r
+\r
// FIXME : cet appel est très lent\r
$("#" + this.getId() + " .messages .message").each(\r
function() {\r
//\r
// You should have received a copy of the GNU General Public License\r
// along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
- \r
+\r
/*jslint laxbreak:true */\r
\r
/**\r
this.formater = formater;\r
this.util = util;\r
this.fragment = fragment;\r
- \r
+\r
// un ensemble des messages (id) auquel l'utilisateur répond (vider après l'envoie du message courant)\r
this.messagesRepond = {};\r
- \r
+\r
this.conversations = []; // les conversations, la première représente la conversation principale\r
- \r
+\r
this.nouvelleConversation(0);\r
- \r
- this.trollIdCourant = 0;\r
- \r
+\r
this.comet = communication.createCometConnection("chat");\r
};\r
\r
* Permet de définir un message comme étant ou n'étant plus un message auquel l'utilisateur\r
* répond.\r
*/\r
-euphorik.Conversations.prototype.toggleMessageRepond = function(mess) { \r
+euphorik.Conversations.prototype.toggleMessageRepond = function(mess) {\r
// est-ce que l'on répond déjà à ce message ? si oui alors on l'enlève de la liste\r
if (mess.id in this.messagesRepond) {\r
this.enleverMessageRepond(mess);\r
return;\r
}\r
- \r
+\r
this.ajouterMessageRepond(mess);\r
};\r
\r
*/\r
euphorik.Conversations.prototype.enleverMessagesRepond = function() {\r
var thisConversations = this;\r
- \r
+\r
objectEach(this.messagesRepond, function(messId, mess) {\r
thisConversations.enleverMessageRepond(mess);\r
});\r
- \r
+\r
// on réinitialise pour être sur que tout est bien enlevé\r
this.messagesRepond = {};\r
$("#conversations .message").removeClass("repondEnEvidence");\r
*/\r
euphorik.Conversations.prototype.ajouterMessageRepond = function(mess) {\r
var thisConversations = this;\r
- \r
+\r
// est-ce que le message fait partie de la même conversation que les autres messages ?\r
// TODO : solution plus élégante pour prendre un mess parmis messagesRepond !?\r
var mess2;\r
break;\r
}\r
}\r
- \r
+\r
if (mess2 && mess2.racineId !== mess.racineId) {\r
this.util.messageDialog("Impossible de répondre à deux messages ne faisant pas partie de la même conversation");\r
return;\r
}\r
- \r
+\r
$("form#posterMessage #repondA .messages").append(mess.XHTML(undefined, this.prefixIdMessage));\r
this.messagesRepond[mess.id] = mess;\r
- \r
+\r
// ajout la classe 'repondEnEvidence' au message. comme il peut se trouver potentiellement dans\r
// chaque conversation on construit tous les id potentiels\r
$(mess.getId(this.prefixIdMessage) + ", " + this.exprIdsPotentiels(mess)).addClass("repondEnEvidence");\r
- \r
+\r
$("#" + mess.getId(this.prefixIdMessage)).click(\r
function() {\r
$(this).fadeOut("normal", function() {\r
euphorik.Conversations.prototype.rafraichireNombreMessagesRepond = function() {\r
// TODO : ya pas mieux pour trouver le nombre d'objet ?\r
var nb = objectMemberCount(this.messagesRepond);\r
- \r
+\r
$("#posterMessage #repondA .nb").text(nb);\r
- \r
+\r
var boite = $("#posterMessage #repondA");\r
if (nb > 0) {\r
boite.show();\r
var mess = {\r
"message_count" : euphorik.conf.nbMessageAffiche,\r
"main_page" : this.client.mainConversationPage,\r
- "conversations" : this.getJSONConversations(),\r
- "troll_id" : this.trollIdCourant\r
+ "conversations" : this.getJSONConversations()\r
};\r
- \r
+\r
if (this.client.cookie) {\r
mess.cookie = this.client.cookie;\r
}\r
mess.last_message_id = this.conversations[0].idDernierMessageAffiche;\r
- \r
+\r
return mess;\r
};\r
\r
euphorik.Conversations.prototype.getJSONConversations = function() {\r
var thisConversations = this;\r
var clientConv = [];\r
- \r
+\r
this.client.conversations.each(function(i, conv) {\r
clientConv.push({\r
root : conv.root,\r
if (!elements.messages.length) {\r
return this.conversations[numConversation] !== undefined;\r
}\r
- \r
+\r
for (var i = 0; i < elements.messages.length; i++) {\r
if (this.ajouterMessage(elements.messages[i], numConversation)) {\r
// si une nouvelle conversation a été créée alors on lui donne la racine\r
this.mettreAJourFragment();\r
}\r
}\r
- \r
+\r
this.flush(numConversation);\r
- \r
+\r
// renseigne la conversation sur la page courante et si c'est la dernière\r
this.conversations[numConversation].setPage(\r
numConversation === 0 ? this.client.mainConversationPage : this.client.conversations[numConversation - 1].page,\r
elements.last_page\r
);\r
- \r
+\r
return true;\r
};\r
\r
* @param numConversation le numéro de la conversation, 0 = principale\r
* @return true si une nouvelle conversation a été créée sinon false\r
*/\r
-euphorik.Conversations.prototype.ajouterMessage = function(element, numConversation) { \r
- var message = \r
+euphorik.Conversations.prototype.ajouterMessage = function(element, numConversation) {\r
+ var message =\r
new euphorik.Message(\r
this.client,\r
this.formater,\r
element\r
);\r
- \r
+\r
var nouvelleConversation = false;\r
- \r
+\r
if (!this.conversations[numConversation]) {\r
nouvelleConversation = true;\r
this.nouvelleConversation(numConversation);\r
var thisConversations = this;\r
\r
this.conversations[num] = new euphorik.Conversation(this, num);\r
- \r
+\r
this.conversations[num].setFunPage(\r
function(num) { // page suivante\r
thisConversations.client.nextPage(num - 1);\r
}\r
}\r
);\r
- \r
+\r
this.ajusterLargeurConversations();\r
};\r
\r
return; // la numéro 0 ne peut être supprimé\r
}\r
this.conversations[num].supprimer();\r
- \r
+\r
// les numéros sont réassigné\r
for (var i = num; i < this.conversations.length - 1; i++) {\r
this.conversations[i] = this.conversations[i+1];\r
}\r
this.conversations.pop();\r
this.ajusterLargeurConversations();\r
- \r
+\r
this.client.supprimerConversation(num - 1);\r
- \r
+\r
this.rafraichirMessages(true);\r
this.mettreAJourFragment();\r
};\r
// le "- 0.01" evite que IE se chie dessus lamentablement et affiche les conversations les unes au dessus des autres\r
//if($.browser["msie"])\r
// largeurPourcent -= 0.05\r
- \r
+\r
$("#conversations td").css("width", largeurPourcent + "%");\r
};\r
\r
/**\r
* Demande à une conversation de se flusher.\r
*/\r
-euphorik.Conversations.prototype.flush = function(numConv) { \r
+euphorik.Conversations.prototype.flush = function(numConv) {\r
this.conversations[numConv].flush();\r
};\r
- \r
+\r
euphorik.Conversations.prototype.ouvrirConversation = function(racine) {\r
if (this.client.ajouterConversation(racine)) {\r
this.rafraichirMessages(true);\r
*/\r
euphorik.Conversations.prototype.rafraichirMessages = function(vider) {\r
var thisConversations = this;\r
- \r
+\r
vider = vider || false;\r
- \r
+\r
if (vider) {\r
this.conversations.each(function(i, conv) {\r
conv.idDernierMessageAffiche = 0;\r
});\r
}\r
-
- thisConversations.util.showWaitBar(); // pour faire patienter le user :)
- \r
+\r
+ thisConversations.util.showWaitBar(); // pour faire patienter le user :)\r
+\r
this.comet.waitEvent(\r
- function() { return thisConversations.getJSONrafraichirMessages(); },\r
{\r
- "new_troll" :\r
- function(data) {\r
- thisConversations.trollIdCourant = data.troll_id;\r
- $("#trollCourant .troll").html(thisConversations.formater.completeProcessing(data.content)).unbind("click").click(\r
- function() {\r
- thisConversations.ouvrirConversation(data.message_id);\r
- }\r
- );\r
- \r
- $("#trollCourant .troll a[@rel*=lightbox]").lightBox();\r
- },\r
"new_messages" :\r
- function(data) {
- \r
+ function(data) {\r
+\r
if (vider) {\r
thisConversations.viderMessages();\r
}\r
- \r
+\r
// ajoute les messages reçus à leur conversation respective\r
data.conversations.each(function(numConv, conv) {\r
if (!thisConversations.ajouterMessages(conv, numConv)) {\r
thisConversations.client.supprimerConversation(numConv - 1);\r
}\r
});\r
- \r
+\r
if (vider) {\r
thisConversations.afficherMessagesRepondConversations();\r
}\r
- \r
- vider = false;
-
+\r
+ vider = false;\r
+\r
thisConversations.util.hideWaitBar();\r
}\r
- }\r
+ },\r
+ function() { return thisConversations.getJSONrafraichirMessages(); }\r
);\r
};\r
//\r
// You should have received a copy of the GNU General Public License\r
// along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
- \r
+\r
euphorik.Reponse = function(id, nick, login) {\r
this.id = id;\r
this.nick = nick || "";\r
euphorik.Message = function(client, formater, element) {\r
this.client = client;\r
this.formater = formater;\r
- \r
+\r
this.id = element.id;\r
this.auteurId = element.user_id;\r
this.racineId = element.root;\r
this.nick = element.nick;\r
this.login = element.login;\r
this.contenu = element.content;\r
- \r
+\r
// l'ensemble des id des messages qui reponde à ce message, exemple : {45:true, 32:true} (le 'true' ne sert à rien ^_^)\r
// mis à jour au fur à mesure que des messages sont ajoutés aux conversations\r
this.estReponduPar = {};\r
- \r
+\r
this.appartientAuClient = element.owner;\r
this.clientARepondu = element.answered;\r
this.estUneReponse = element.is_a_reply;\r
euphorik.Message.prototype.setRepondA = function(repondAJSON) {\r
var thisMessage = this;\r
this.repondA = {};\r
- \r
+\r
repondAJSON.each(function(i, reponse) {\r
thisMessage.repondA[reponse.id] = new euphorik.Reponse(reponse.id, reponse.nick, reponse.login);\r
});\r
// les messages faisant partie de la conversation\r
var messagesEnEvidence = {};\r
messagesEnEvidence[this.id] = 1;\r
- \r
+\r
// parcours en profondeur\r
var f = function(ids, premierNiveau, ensemble, evidence) {\r
objectEach(ids, function(id) {\r
}\r
});\r
};\r
- \r
+\r
// remonte le temps\r
f(this.estReponduPar, true, "estReponduPar", 2);\r
- \r
+\r
// descent le temps\r
- f(this.repondA, true, "repondA", 3); \r
- \r
+ f(this.repondA, true, "repondA", 3);\r
+\r
return messagesEnEvidence;\r
};\r
\r
messagePair = true;\r
}\r
pre = pre || "";\r
- \r
+\r
thisMessage = this;\r
- \r
+\r
// construit l'identifiant de la personne\r
- var identifiant = \r
- this.client.nickFormat === "nick" || this.login === "" ? this.formater.completeProcessing(this.nick) : \r
- (this.client.nickFormat === "login" ? this.formater.completeProcessing(this.login) : \r
+ var identifiant =\r
+ this.client.nickFormat === "nick" || this.login === "" ? this.formater.completeProcessing(this.nick) :\r
+ (this.client.nickFormat === "login" ? this.formater.completeProcessing(this.login) :\r
this.formater.completeProcessing(this.nick) + "<span class=\"login\">(" + this.formater.completeProcessing(this.login) +")</span>" );\r
\r
var XHTMLrepondA = "";\r
if (XHTMLrepondA) {\r
XHTMLrepondA = "<span class=\"repondA\">" + XHTMLrepondA + "</span><span class=\"delimitationRepondA\"></span>";\r
}\r
- \r
+\r
return "<div id=\"" + this.getId(pre) + "\" class=\"" + (messagePair ? "messagePair" : "messageImpair") + " message" +\r
(this.appartientAuClient ? " proprietaire" : "") +\r
(this.clientARepondu ? " repondu" : "") +\r
"<span class=\"entete\">" +\r
"<span class=\"dateComplete\">[<span class=\"date\">" + this.date + "</span>]</span>" +\r
"<span class=\"nick\"><span class=\"id\" style=\"display: none\">" + this.auteurId + "</span><span class=\"ident\">" + identifiant + "</span></span>" +\r
- "</span>" + \r
+ "</span>" +\r
"<span class=\"delimitationEntete\"></span>" +\r
XHTMLrepondA +\r
"<span class=\"contenu\">" + this.formater.completeProcessing(this.contenu, this.nick) + "</span>" +\r
// Regroupe la partie communication JSON client -> serveur de euphorik.\r
// Voir : http://dev.euphorik.ch/wiki/euk/Protocole\r
\r
-/**
- * Les fonctions debutReq et finReq servent, par exemple, à afficher à l'utilisateur
+/**\r
+ * Les fonctions debutReq et finReq servent, par exemple, à afficher à l'utilisateur\r
* qu'une communication est en cours.\r
- * @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 funError un fonction executée lors d'un réponse 'error' de la part du serveur, peut être redéfinit pour une requête.\r
+ * @param funDebutReq fonction appelée au début d'une requête (facultatif)\r
* @param funFinReq fonction appelée à la fin d'une requête (facultatif)\r
*/\r
euphorik.Communication = function(funError, funDebutReq, funFinReq) {\r
- this.funError = funError;
- this.funDebutReq = funDebutReq;
+ this.funError = funError;\r
+ this.funDebutReq = funDebutReq;\r
this.funFinReq = funFinReq;\r
-};
-
-/**
- * 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;
};\r
-
-/**
- * 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)
+\r
+/**\r
+ * Charge un fichier depuis une url et retourne son contenu.\r
+ */\r
+euphorik.Communication.prototype.load = function(url) {\r
+ if (this.funDebutReq) {\r
+ this.funDebutReq();\r
+ }\r
+ var contenu = "";\r
+ $.ajax({async: false, url: url, success : function(page) { contenu += page; }});\r
+ if (this.funFinReq) {\r
+ this.funFinReq();\r
+ }\r
+ return contenu;\r
+};\r
+\r
+/**\r
+ * Effectue une requête JSON auprès du serveur.\r
+ * @param action une chaine spécifiant l'action, par exemple "put_message"\r
+ * @param json les données à envoyer associé à l'action, par exemple {"cookie" : "LKJDLAKSJBFLKASN", "nick" : "Paul", "content" : "Bonjour", "answer_to" : [] }\r
+ * @param funOk la fonction exécuté après réception des données du serveur\r
+ * @param funError la fonction exécuté si une erreur arrive (facultatif)\r
+ * @param asynchrone true pour une communication asychrone (facultatif, truepar défaut)\r
+ * @param paramsSupp un objet contenant des paramètres supplémentaire pour la fonction ajax de jQuery (facultatif)\r
*/\r
euphorik.Communication.prototype.requete = function(action, json, funOk, funError, asynchrone, paramsSupp) {\r
var thisCommunication = this;\r
var mess = this.getBase(action);\r
objectEach(json, function(name, val) {\r
mess[name] = val;\r
- });
-
- if (this.funDebutReq) {
- this.funDebutReq();
+ });\r
+\r
+ if (this.funDebutReq) {\r
+ this.funDebutReq();\r
}\r
- \r
+\r
paramsAjax = {\r
async: asynchrone,\r
type: "POST",\r
dataType: "json",\r
data: { action : JSON.stringify(mess) },\r
success:\r
- function(data) {
- if (thisCommunication.funFinReq) {
- thisCommunication.funFinReq();
+ function(data) {\r
+ if (thisCommunication.funFinReq) {\r
+ thisCommunication.funFinReq();\r
}\r
if (data.reply === "error") {\r
if (funError) {\r
} else if (funOk) {\r
funOk(data);\r
}\r
- },
- error:
- function(data) {
- if (thisCommunication.funFinReq) {
- thisCommunication.funFinReq();
- }
+ },\r
+ error:\r
+ function(data) {\r
+ if (thisCommunication.funFinReq) {\r
+ thisCommunication.funFinReq();\r
+ }\r
}\r
};\r
- \r
+\r
if (paramsSupp) {\r
objectEach(paramsSupp, function(name, val) {\r
paramsAjax[name] = val;\r
});\r
}\r
- \r
+\r
jQuery.ajax(paramsAjax);\r
};\r
-
-euphorik.Communication.prototype.createCometConnection = function(name) {
- return new Comet(name, this.getBase);
-};
+\r
+euphorik.Communication.prototype.createCometConnection = function(name) {\r
+ return new Comet(name, this.getBase);\r
+};\r
\r
euphorik.Communication.prototype.getBase = function(action) {\r
return {\r
"header" : { "action" : action, "version" : euphorik.conf.versionProtocole }\r
};\r
-};
-
-/**
- * Permet de gérer les événements (push serveur).
- * Principe de fonctionnement :
- * - La page courante créer un objet euphorik.Comet en indiquant le nom de la page et la version du protocole.
- * - La page courante attend un événement en appelant 'waitEvent' (non-bloquant) et en donnant deux fonctions :
- * - 'funSend' une fonction qui renvoie l'objet à envoyer avant l'attente, par exemple {"dernierMess" : 23}
- * ("header" et "page" sont automatiquement ajoutés à l'objet)
- * - 'funsReceive' un ensemble de fonctions à appeler en fonction du "reply" du serveur, par exemple {"set_nom" : function(data) { print("ok : " + data.nom); } }
- *
- * l'information envoyée est sous la forme :
- * {
- * "header" : {"action" : "wait_event", "version" : <v> },
- * "page" : <page>
- * [..]
- * }
- * l'information reçue est sous la forme :
- * {
- * "reply" : <reply>
- * [..]
- * }
- * <reply> et <page> sont de type chaine
- *
- * @page [string] la page courante pour laquelle on écoute des événements (un string)
- * @util [int] la version
- */
-Comet = function(page, getBase) {
- this.page = page;
- this.getBase = getBase;
-
- // l'objet JSONHttpRequest représentant la connexion d'attente
- this.attenteCourante = undefined;
-
- // le multhreading du pauvre, merci javascript de m'offrire autant de primitives pour la gestion de la concurrence...
- this.stop = false;
-};
-
-/**
- * Arrête l'attente courante s'il y en a une.
- */
-Comet.prototype.stopAttenteCourante = function() {
- this.stop = true;
-
- if (this.attenteCourante) {
- this.attenteCourante.abort();
- }
-};
-
-/**
- * Attend un événement lié à la page. Non-bloquant.
- * @funSend une fonction renvoyant les données json à envoyer
- * @funsReceive est un objet comprenant les fonctions à appeler en fonction du "reply"
- * les fonctions acceptent un paramètre correspondant au données reçues.
- * exemple : {"new_message" : function(data){ ... }}
- */
-Comet.prototype.waitEvent = function(funSend, funsReceive) {
- this.stopAttenteCourante();
- this.stop = false;
- var thisComet = this;
-
- // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veut dans l'ordre définit dans le protocole)
- // TODO : ya pas mieux ?
- var dataToSend = this.getBase("wait_event")
- dataToSend["page"] = this.page;
-
- var poulpe = funSend();
- objectEach(poulpe, function(k, v) {
- dataToSend[k] = v;
- });
-
- this.attenteCourante = jQuery.ajax({
- type: "POST",
- url: "request",
- dataType: "json",
- // TODO : doit disparaitre
- timeout: 180000, // timeout de 3min. Gros HACK pas beau. FIXME problème décrit ici : http://groups.google.com/group/jquery-en/browse_thread/thread/8724e64af3333a76
- data: { action : JSON.stringify(dataToSend) },
- success:
- function(data) {
- funsReceive[data.reply](data);
-
- // rappel de la fonction dans 100 ms
- setTimeout(function(){ thisComet.waitEvent2(funSend, funsReceive); }, 100);
- },
- error:
- function(XMLHttpRequest, textStatus, errorThrown) {
- ;; console.log("Connexion perdue dans Comet.prototype.waitEvent() : \n" + textStatus);
- setTimeout(function(){ thisComet.waitEvent2(funSend, funsReceive); }, 1000);
- }
- });
-};
-
-/**
- * Si un stopAttenteCourante survient un peu n'importe quand il faut imédiatement arreter de boucler.
- */
-Comet.prototype.waitEvent2 = function(funSend, funsReceive) {
- if (this.stop) {
- return;
- }
- this.waitEvent(funSend, funsReceive);
+};\r
+\r
+/**\r
+ * Permet de gérer les événements (push serveur).\r
+ * Principe de fonctionnement :\r
+ * - La page courante créer un objet euphorik.Comet en indiquant le nom de la page et la version du protocole.\r
+ * - La page courante attend un événement en appelant 'waitEvent' (non-bloquant) et en donnant deux fonctions :\r
+ * - 'funsReceive' un ensemble de fonctions à appeler en fonction du "reply" du serveur, par exemple {"set_nom" : function(data) { print("ok : " + data.nom); } }\r
+ * - 'funSend' une fonction qui renvoie l'objet à envoyer avant l'attente, par exemple {"dernierMess" : 23}\r
+ * ("header" et "page" sont automatiquement ajoutés à l'objet)\r
+ *\r
+ * l'information envoyée est sous la forme :\r
+ * {\r
+ * "header" : {"action" : "wait_event", "version" : <v> },\r
+ * "page" : <page>\r
+ * [..]\r
+ * }\r
+ * l'information reçue est sous la forme :\r
+ * {\r
+ * "reply" : <reply>\r
+ * [..]\r
+ * }\r
+ * <reply> et <page> sont de type chaine\r
+ *\r
+ * @page [string] la page courante pour laquelle on écoute des événements (un string)\r
+ * @util [int] la version\r
+ */\r
+Comet = function(page, getBase) {\r
+ this.page = page;\r
+ this.getBase = getBase;\r
+\r
+ // l'objet JSONHttpRequest représentant la connexion d'attente\r
+ this.attenteCourante = undefined;\r
+\r
+ // le multhreading du pauvre, merci javascript de m'offrire autant de primitives pour la gestion de la concurrence...\r
+ this.stop = false;\r
+};\r
+\r
+/**\r
+ * Arrête l'attente courante s'il y en a une.\r
+ */\r
+Comet.prototype.stopAttenteCourante = function() {\r
+ this.stop = true;\r
+\r
+ if (this.attenteCourante) {\r
+ this.attenteCourante.abort();\r
+ }\r
+};\r
+\r
+/**\r
+ * Attend un événement lié à la page. Non-bloquant.\r
+ * @funsReceive est un objet comprenant les fonctions à appeler en fonction du "reply"\r
+ * les fonctions acceptent un paramètre correspondant au données reçues.\r
+ * exemple : {"new_message" : function(data){ ... }}\r
+ * @funSend une fonction renvoyant les données json à envoyer (optional)\r
+ */\r
+Comet.prototype.waitEvent = function(funsReceive, funSend) {\r
+ this.stopAttenteCourante();\r
+ this.stop = false;\r
+ var thisComet = this;\r
+\r
+ // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veut dans l'ordre définit dans le protocole)\r
+ // TODO : ya pas mieux ?\r
+ var dataToSend = this.getBase("wait_event")\r
+ dataToSend["page"] = this.page;\r
+\r
+ if (funSend !== undefined) {\r
+ var tmp = funSend();\r
+ objectEach(tmp, function(k, v) {\r
+ dataToSend[k] = v;\r
+ });\r
+ }\r
+\r
+ this.attenteCourante = jQuery.ajax({\r
+ type: "POST",\r
+ url: "request",\r
+ dataType: "json",\r
+ // TODO : doit disparaitre\r
+ timeout: 180000, // timeout de 3min. Gros HACK pas beau. FIXME problème décrit ici : http://groups.google.com/group/jquery-en/browse_thread/thread/8724e64af3333a76\r
+ data: { action : JSON.stringify(dataToSend) },\r
+ success:\r
+ function(data) {\r
+ funsReceive[data.reply](data);\r
+\r
+ // rappel de la fonction dans 100 ms\r
+ setTimeout(function(){ thisComet.waitEvent2(funsReceive, funSend); }, 100);\r
+ },\r
+ error:\r
+ function(XMLHttpRequest, textStatus, errorThrown) {\r
+ // console.log("Connexion perdue dans Comet.prototype.waitEvent() : \n" + textStatus);\r
+ setTimeout(function(){ thisComet.waitEvent2(funsReceive, funSend); }, 1000);\r
+ }\r
+ });\r
+};\r
+\r
+/**\r
+ * Si un stopAttenteCourante survient un peu n'importe quand il faut imédiatement arreter de boucler.\r
+ */\r
+Comet.prototype.waitEvent2 = function(funsReceive, funSend) {\r
+ if (this.stop) {\r
+ return;\r
+ }\r
+ this.waitEvent(funsReceive, funSend);\r
};
\ No newline at end of file
//
// You should have received a copy of the GNU General Public License
// along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
-//
+//
// La page d'administation, ne peut être accédée que par les ekMaster (admins)
/*jslint laxbreak:true */
euphorik.PageAdmin = function(client, formater, util, communication) {
this.name = "admin";
-
+
this.client = client;
this.formater = formater;
this.util = util;
this.communication = communication;
-
+
this.comet = this.communication.createCometConnection("admin");
-
+
// a timer which will periodically refresh the banned IP list
this.timeoutIDmajIPs = null;
};
* Interface des pages.
*/
euphorik.PageAdmin.prototype.contenu = function() {
- return '<h1>Trolls</h1>' +
- '<p>Un troll est un sujet à débat, en général une question, affiché sur la page principale.</p>' +
- '<p>Chaque semaine un troll est choisi au hasard parmis les trolls proposés et devient le troll de la semaine.</p>' +
- '<form action="" id="nouveauTroll">' +
- ' <p>' +
- ' <input class="troll" name="troll" type="text" maxlength="500" value=""></input>' +
- ' <button class="return" value="return">poster</button>' +
- ' </p>' +
- '</form>' +
- '<div id="trolls"></div>' +
- '<h1>IPs bannies</h1>' +
- '<div id="ips"></div>';
+ return '<h1>IPs bannies</h1><div id="ips"></div>';
};
/**
* Interface des pages.
*/
-euphorik.PageAdmin.prototype.charger = function() {
- $("#page form#nouveauTroll").submit(function(){ return false; });
-
+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.formater, this.communication);
-
+
this.waitEvent();
-
+
this.majIPs();
-
- $("#page form#nouveauTroll input.troll").focus();
-
- $("#page form#nouveauTroll button.return").click(
- function() {
- thisPage.posterTroll();
- }
- );
};
/**
*/
euphorik.PageAdmin.prototype.decharger = function() {
this.comet.stopAttenteCourante();
-
+
// supprime le rafraichissement période des ips
if (this.timeoutIDmajIPs) {
clearTimeout(this.timeoutIDmajIPs);
}
};
-/**
- * Post un troll, le contenu est lu à partir de "input.troll".
- */
-euphorik.PageAdmin.prototype.posterTroll = function() {
- var thisPageAdmin = this;
-
- var content = $("#page form#nouveauTroll input.troll").val();
-
- content = content.trim();
- if (content === "") {
- this.util.messageDialog("Le troll est vide");
- return;
- }
-
- this.communication.requete(
- "put_troll",
- {"cookie" : this.client.cookie, "content" : content},
- function(data) {
- $("#page form#nouveauTroll input.troll").val("");
- }
- );
-};
-
/**
* Met à jour la liste des IP bannies.
*/
}
var thisPageAdmin = this;
-
+
this.communication.requete(
"list_banned_ips",
{"cookie" : this.client.cookie},
- function(data) {
+ function(data) {
var XHTML = "";
data.list.each(function(i, ip) {
XHTML += '<div class="ban"><span class="ip">' + ip.ip + '</span>|' +
});
XHTML += '<span class="deban">débannir</span></div>';
});
-
+
if (data.list.length === 0) {
XHTML += '<p>Aucune IP bannie</p>';
}
-
+
$("#ips").html(XHTML);
-
+
$(".ban").each(function() {
var ip = $(".ip", this).html();
$(".deban", this).click(
}
);
});
-
+
// 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);
*/
euphorik.PageAdmin.prototype.deban = function(ip) {
var thisPageAdmin = this;
-
+
this.communication.requete(
- "unban",
+ "unban",
{"cookie" : this.client.cookie, "ip" : ip}
);
};
*/
euphorik.PageAdmin.prototype.waitEvent = function() {
var thisPageAdmin = this;
-
+
this.comet.waitEvent(
- function() { return { "last_troll" : thisPageAdmin.trolls.dernierTroll }; },
{
- "troll_added" : function(data){ thisPageAdmin.trolls.ajouterTrollEvent(data); },
- "troll_modified" : function(data){ thisPageAdmin.trolls.modifierTrollEvent(data); },
- "troll_deleted" : function(data){ thisPageAdmin.trolls.supprimerTrollEvent(data); },
"banned_ips_refresh" : function(data){ thisPageAdmin.majIPs(); },
"error" :
function(data) {
- thisTrolls.util.messageDialog(data.error_message);
- }
- }
- );
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-/**
- * Représente un troll, pas grand chose finalement.
- */
-euphorik.Troll = function(content, author) {
- this.content = content;
- this.author = author;
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-euphorik.Trolls = function(client, util, formater, communication) {
- this.client = client;
- this.util = util;
- this.formater = formater;
- this.communication = communication;
- this.dernierTroll = 0;
-
- this.trolls = {};
-};
-
-euphorik.Trolls.prototype.ajouterTrollEvent = function(data) {
- var thisTrolls = this;
-
- var XHTML = "";
- data.trolls.each(function(i, trollData) {
- var troll = new euphorik.Troll(trollData.content, trollData.author);
- var trollId = trollData.troll_id;
- thisTrolls.trolls[trollId] = troll;
-
- XHTML +=
- '<div id="troll' + trollId + '" class="troll">' +
- '<span class="content">' + thisTrolls.formater.completeProcessing(troll.content, troll.author) + '</span>' +
- '<span class="author"> - ' + thisTrolls.formater.completeProcessing(troll.author) + '</span>' +
- (trollData.author_id === thisTrolls.client.id ? '<span class="editTroll">éditer</span><span class="delTroll">Supprimer</span>' : '') +
- '</div>';
- });
- $("#trolls").append(XHTML);
- $("#trolls .troll").filter(function() { return parseInt($(this).attr("id").substr(5), 10) > thisTrolls.dernierTroll; }).each(
- function() {
- var troll = this;
- var id = parseInt($(this).attr("id").substr(5), 10);
-
- $("a[@rel*=lightbox]", this).lightBox();
-
- $(this).keypress(
- function(e) {
- if (e.which === 13) { // return
- $(".modifier", this).click();
- }
- }
- );
-
- $(".delTroll", this).click(
- function() {
- thisTrolls.util.messageDialog(
- "Êtes-vous sur de vouloir supprimer le troll \"" + thisTrolls.trolls[id].content + "\" ?",
- euphorik.Util.messageType.question,
- {
- "oui" : function() {
- thisTrolls.supprimer(id);
- },
- "non" : function(){}
- }
- );
- }
- );
-
- $(".editTroll", this).click(
- function() {
- $("span", troll).css("display", "none");
- $(troll).append(
- '<form><p><input class="content" type="text" size="50" maxlength="500" value="' +
- thisTrolls.trolls[id].content +
- '"></input><span class="modifier">modifier</span><span class="annuler">annuler</span></p></form>'
- );
- $("form input.content").focus();
-
- var virerLeFormulaire = function() {
- $('form', troll).remove();
- $('span', troll).css("display", "inline");
- };
- $("span.modifier", troll).click(
- function() {
- var content = $("form input.content", troll).val();
- virerLeFormulaire();
- thisTrolls.modifier(id, content);
- }
- );
- $("span.annuler", troll).click( virerLeFormulaire );
- $("form", troll).submit(function(){ return false; });
+ thisPage.util.messageDialog(data.error_message);
}
- );
}
);
-
- if (data.trolls.length > 0) {
- thisTrolls.dernierTroll = data.trolls[data.trolls.length - 1].troll_id;
- }
-};
-
-euphorik.Trolls.prototype.modifierTrollEvent = function(data) {
- var thisTrolls = this;
- $("#trolls #troll" + data.troll_id + " .content").html(thisTrolls.formater.completeProcessing(data.content, thisTrolls.trolls[data.troll_id].author));
- $("#trolls #troll" + data.troll_id + " a[@rel*=lightbox]").lightBox();
- thisTrolls.trolls[data.troll_id].content = data.content;
-};
-
-euphorik.Trolls.prototype.supprimerTrollEvent = function(data) {
- $("#trolls #troll" + data.troll_id).remove();
-};
-
-euphorik.Trolls.prototype.modifier = function(id, content) {
- 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) {
- this.communication.requete(
- "del_troll",
- {"cookie" : this.client.cookie, "troll_id" : id}
- );
-};
+};
\ No newline at end of file
//
// You should have received a copy of the GNU General Public License
// along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
-
+
/*jslint laxbreak:true */
euphorik.PageMinichat = function(client, formater, util, communication) {
this.name = "minichat";
-
+
this.client = client;
this.formater = formater;
this.util = util;
this.communication = communication;
this.commandes = new euphorik.Commandes(this.client, this, this.util, this.formater);
-
+
// permet d'éviter d'envoyer plusieurs messages simultanément en pressant
// rapidement sur "enter" par exemple
this.envoieMessageEnCours = false;
' <button class="return"></button>' +
' </p>' +
'</form>';
-
- var trollXHTML = '<div id="trollCourant">Troll de la semaine : <span class="troll"></span></div>';
+
var conversationXHTML = '<table id="conversations"><tr></tr></table>';
-
+
if (this.client.chatOrder === "reverse") {
- return trollXHTML + formulaireXHTML + conversationXHTML;
+ return formulaireXHTML + conversationXHTML;
} else {
- return trollXHTML + conversationXHTML + formulaireXHTML;
+ return conversationXHTML + formulaireXHTML;
}
};
euphorik.PageMinichat.prototype.charger = function() {
thisPage = this;
-
+
$("#posterMessage input.nick").val(this.client.nick);
-
+
// cet appel ne doit pas être fait avant l'appel à 'charger'
- this.conversations = new euphorik.Conversations(this.client, this.formater, this.util, this.communication, this.fragment);
-
+ this.conversations = new euphorik.Conversations(this.client, this.formater, this.util, this.communication, this.fragment);
+
this.chargerConversationsFragment();
-
- this.conversations.rafraichirMessages(true);
+
+ this.conversations.rafraichirMessages(true);
this.util.setCaretToEnd($("form#posterMessage input.message")[0]);
// les outils de bannissement (uniquement pour les ekMaster)
- if (this.client.ekMaster) {
+ if (this.client.ekMaster) {
// TODO : augmentation un peu space, à revoir
this.util.outilsBan = $(
'<span id="outilsBan">' +
' <img id="slap" src="img/slap.gif" alt="Avertissement" />' +
'</span>'
);
-
+
this.util.infoBulle("Slap", $("#slap", this.util.outilsBan));
this.util.infoBulle("Kick (" + euphorik.conf.tempsKick + "min)", $("#kick", this.util.outilsBan));
this.util.infoBulle("Ban (" + euphorik.conf.tempsBan / 24 / 60 + " jours)", $("#ban", this.util.outilsBan));
this.util.infoBulle("La raison", $("input", this.util.outilsBan));
}
-
+
// la barre d'outils liée à chaque message
- this.util.outilsMessage = $('<div id="outilsMess"><div class="extraire"></div><div class="extraireCompletement"></div></div>').prependTo("#page.minichat");
- this.util.infoBulle("Ouvrir la conversation liée au troll de la semaine", $("#trollCourant .troll"));
+ this.util.outilsMessage = $('<div id="outilsMess"><div class="extraire"></div><div class="extraireCompletement"></div></div>').prependTo("#page.minichat");
this.util.infoBulle("Cliquer sur les messages pour les enlevers de la liste",
$("form#posterMessage #repondA").hover(
function() {
if ($(e.target).is(".nb")) {
thisPage.conversations.enleverMessagesRepond();
}
- }
+ }
),
euphorik.Util.positionBulleType.droite
);
}
);
// </smiles>
-
+
// événements
- var nouveauMessage =
- function() {
+ var nouveauMessage =
+ function() {
// captcha anti bot
if ($("form#posterMessage input.captcha").val() !== "") {
return;
}
-
+
var message = $("form#posterMessage input.message").val();
-
+
// traitement des commandes..
- var retCommandes = thisPage.commandes.exec(message);
+ var retCommandes = thisPage.commandes.exec(message);
switch (retCommandes[0]) {
case euphorik.Commandes.statut.pas_une_commande :
thisPage.envoyerMessage(message);
case euphorik.Commandes.statut.ok :
$("form#posterMessage input.message").val("");
break;
- }
-
+ }
+
$("form#posterMessage input.message").focus();
};
-
+
$("form#posterMessage").keypress(
function(e) {
if (e.which === 13) { // return
}
}
);
-
+
$("form#posterMessage button.return").click(nouveauMessage);
-
+
// interdiction de submiter le formulaire
$("form#posterMessage").submit(function(){ return false; });
-
+
$("input.nick").click(
function() {
var input = $("input.nick")[0];
};
euphorik.PageMinichat.prototype.chargerConversationsFragment = function() {
- var thisPageMinichat = this;
-
+ var thisPageMinichat = this;
+
// attention : "conv" doit être un tableau d'entier
try {
var conv = this.fragment.getVal("conv");
;; console.log(e)
}
};
-
+
euphorik.PageMinichat.prototype.decharger = function() {
this.conversations.comet.stopAttenteCourante();
-
+
$("body #smiles").remove();
-
+
this.fragment.delVal("conv");
};
* Envoie un nouve message donné, le nick utilisé est celui se trouvant
* dans la zone de saisie (form#posterMessage input.nick).
*/
-euphorik.PageMinichat.prototype.envoyerMessage = function(message) {
- var thisPageMinichat = this;
+euphorik.PageMinichat.prototype.envoyerMessage = function(message) {
+ var thisPageMinichat = this;
var nick = $("form#posterMessage input.nick").val();
// (un nick vide est autorisé)
nick = this.formater.formatNick(nick);
-
+
if (nick === euphorik.conf.defaultNick) {
- this.util.messageDialog("Le nick ne peut pas être " + euphorik.conf.defaultNick);
+ this.util.messageDialog("Choose a nickname");
return;
}
-
+
message = message.trim();
if (!message) {
- this.util.messageDialog("Le message est vide");
+ this.util.messageDialog("The message is empty");
return;
}
-
+
if (!this.client.authentifie()) {
if (!this.client.enregistrement()) {
- this.util.messageDialog("login impossible");
+ this.util.messageDialog("unable to login");
return;
}
}
-
+
// évite le double post
if (this.envoieMessageEnCours) {
this.util.messageDialog("Message en cours d'envoie...");
return;
}
this.envoieMessageEnCours = true;
-
+
this.client.nick = nick;
-
+
this.communication.requete(
"put_message",
this.getJSONMessage(this.client.nick, message),
function() {
$("form#posterMessage input.message").val("");
- thisPageMinichat.conversations.enleverMessagesRepond();
+ thisPageMinichat.conversations.enleverMessagesRepond();
thisPageMinichat.envoieMessageEnCours = false;
},
function(data) {
objectEach(this.conversations.messagesRepond, function(id) {
repondA.push(parseInt(id, 10));
});
-
+
return {
"cookie" : this.client.cookie,
"nick" : nick,
$("#info .close").click(function() {\r
$("#info").slideUp(50);\r
});\r
- \r
+\r
$("body").append('<div id="tooltipArrow"></div>').append('<div id="tooltipMessage"><p></p></div>');\r
- \r
+\r
this.formater = formater;\r
this.bulleActive = true;\r
};\r
* @buttons An object where the properties are the labels and the values are functions which will be executed when a button is clicked.\r
* @format [bool] The message should be formated. (see 'formater.js')\r
* @time The time while the message is displayed. -1 for infinity.\r
- */ \r
+ */\r
euphorik.Util.prototype.messageDialog = function(message, type, buttons, format, time) {\r
var thisUtil = this;\r
\r
if (this.timeoutMessageDialog) {\r
clearTimeout(this.timeoutMessageDialog);\r
}\r
- \r
+\r
var close = function() { $("#info").slideUp(100); };\r
close();\r
\r
$("#info .message").html(!thisUtil.formater || !format ? message : thisUtil.formater.completeProcessing(message));\r
- \r
+\r
switch(type) {\r
case euphorik.Util.messageType.informatif : $("#info #icone").attr("class", "information"); break;\r
case euphorik.Util.messageType.question : $("#info #icone").attr("class", "interrogation"); break;\r
case euphorik.Util.messageType.erreur : $("#info #icone").attr("class", "exclamation"); break;\r
}\r
- \r
+\r
$("#info .buttons").html("");\r
objectEach(buttons, function(name, bouton) {\r
$("#info .buttons").append("<div>" + name + "</div>").find("div:last").click(bouton).click(close);\r
});\r
- \r
- $("#info").slideDown(200);
+\r
+ $("#info").slideDown(200);\r
if (time !== -1) {\r
- this.timeoutMessageDialog = setTimeout(close, time || euphorik.conf.tooltipDisplayDefaultTime);
+ this.timeoutMessageDialog = setTimeout(close, time || euphorik.conf.tooltipDisplayDefaultTime);\r
}\r
};\r
\r
var positionCible = cible.offset();\r
var positionBoite = {\r
left : positionX === euphorik.Util.positionTypeX.gauche ? positionCible.left - boite.width() :\r
- (positionX === euphorik.Util.positionTypeX.gaucheRecouvrement ? positionCible.left - boite.width() + cible.width() : \r
+ (positionX === euphorik.Util.positionTypeX.gaucheRecouvrement ? positionCible.left - boite.width() + cible.width() :\r
(positionX === euphorik.Util.positionTypeX.droitelsRecouvrement ? positionCible.left :\r
(positionX === euphorik.Util.positionTypeX.droite ? positionCible.left + cible.width() :\r
positionCible.left + cible.width() / 2 - boite.width() / 2 ))), // centre\r
top : positionY === euphorik.Util.positionTypeY.haut ? positionCible.top - boite.height() :\r
- (positionY === euphorik.Util.positionTypeY.hautRecouvrement ? positionCible.top - boite.height() + cible.height() : \r
+ (positionY === euphorik.Util.positionTypeY.hautRecouvrement ? positionCible.top - boite.height() + cible.height() :\r
(positionY === euphorik.Util.positionTypeY.basRecouvrement ? positionCible.top :\r
(positionY === euphorik.Util.positionTypeY.bas ? positionCible.top + cible.height() :\r
positionCible.top + cible.height() / 2 - boite.height() / 2 ))) // centre\r
};\r
- \r
+\r
// calcul les décalages en x et en y pour éviter que la boite ne sorte de la fenêtre, tient compte de la position des barres de défilement\r
- var marge = 10; \r
+ var marge = 10;\r
positionBoite.left = positionBoite.left < marge + window.pageXOffset ? marge + window.pageXOffset :\r
(boite.width() - $(window).width() + (positionBoite.left - window.pageXOffset) + marge > 0 ? $(window).width() - boite.width() - marge + window.pageXOffset : positionBoite.left);\r
positionBoite.top = positionBoite.top < marge + window.pageYOffset ? marge + window.pageYOffset :\r
(boite.height() - $(window).height() + (positionBoite.top - window.pageYOffset) + marge > 0 ? $(window).height() - boite.height() - marge + window.pageYOffset : positionBoite.top);\r
- \r
+\r
boite.css("top", positionBoite.top).css("left", positionBoite.left).show();\r
};\r
\r
euphorik.Util.positionBulleType = {haut : 0, droite : 1, bas : 2, gauche : 3};\r
-
-/**
- * Affiche ou cache la barre d'attente.
- */
-euphorik.Util.prototype.showWaitBar = function() {
- $("#waitbar").show();
-};
-euphorik.Util.prototype.hideWaitBar = function() {
- $("#waitbar").hide();
-};
+\r
+/**\r
+ * Affiche ou cache la barre d'attente.\r
+ */\r
+euphorik.Util.prototype.showWaitBar = function() {\r
+ $("#waitbar").show();\r
+};\r
+euphorik.Util.prototype.hideWaitBar = function() {\r
+ $("#waitbar").hide();\r
+};\r
\r
/**\r
* Affiche un info bulle lorsque le curseur survole l'élément donné.\r
*/\r
euphorik.Util.prototype.infoBulle = function(message, element, position) {\r
var thisUtil = this;\r
- var cacherBulle = function() { \r
+ var cacherBulle = function() {\r
$("#tooltipArrow").hide();\r
$("#tooltipMessage").hide();\r
};\r
- \r
+\r
position = position || euphorik.Util.positionBulleType.haut;\r
\r
element.hover(\r
var m = $("#tooltipMessage");\r
var f = $("#tooltipArrow");\r
f.removeClass().addClass(position === euphorik.Util.positionBulleType.haut ? "tooltipArrowTop" :\r
- (position === euphorik.Util.positionBulleType.droite ? "tooltipArrowRight" : \r
+ (position === euphorik.Util.positionBulleType.droite ? "tooltipArrowRight" :\r
(position === euphorik.Util.positionBulleType.bas ? "tooltipArrowBottom" : "tooltipArrowLeft" )));\r
- \r
+\r
// remplie le paragraphe de la bulle avec le message\r
$("p", m).html(message);\r
- \r
+\r
// réinitialise la position, évite le cas ou la boite est collé à droite et remplie avec un texte la faisant dépassé\r
// dans ce cas la hauteur n'est pas calculé correctement\r
m.css("top", 0).css("left", 0);\r
- \r
+\r
var positionFleche = {\r
left : position === euphorik.Util.positionBulleType.haut || position === euphorik.Util.positionBulleType.bas ?\r
element.offset().left + element.outerWidth() / 2 - f.width() / 2 :\r
} else if (positionMessage.left < 0) {\r
positionMessage.left = 0;\r
}\r
- \r
+\r
m.css("top", positionMessage.top).css("left", positionMessage.left).show();\r
f.css("top", positionFleche.top).css("left", positionFleche.left).show();\r
},\r
var selectionStart = input.selectionStart;\r
var selectionEnd = input.selectionEnd;\r
input.value = input.value.substring(0, selectionStart) + replaceString + input.value.substring(selectionEnd);\r
- \r
+\r
if (selectionStart != selectionEnd) { // has there been a selection\r
this.setSelectionRange(input, selectionStart, selectionStart + replaceString.length);\r
} else { // set caret\r
};\r
\r
/**\r
- * Applies rot13 to a given string. See : http://en.wikipedia.org/wiki/ROT13.
+ * Applies rot13 to a given string. See : http://en.wikipedia.org/wiki/ROT13.\r
* @param str the string.\r
*/\r
euphorik.Util.prototype.rot13 = function(str) {\r
if (pos === ch.length) {\r
return "";\r
}\r
- \r
+\r
var c = ch.charCodeAt(pos);\r
return String.fromCharCode(\r
c +\r
# coding: utf-8\r
# For more informations about the modules listed here see : http://dev.euphorik.ch/wiki/euk/Home\r
\r
-# Directory where the compiled modules will be put
-rep_ebin = ebin
+# Directory where the compiled modules will be put\r
+rep_ebin = ebin\r
\r
-# Directory where the sources are
-rep_erl = erl
+# Directory where the sources are\r
+rep_erl = erl\r
\r
-# Directory which contains the hrl files (records definition)
-rep_include = include
+# Directory which contains the hrl files (records definition)\r
+rep_include = include\r
+rep_include_yaws = /usr/lib/yaws/include\r
\r
# Arguments for the compilator\r
-# It's possible to compile in native mode with :
-# $ make NATIVE=true
-ifdef NATIVE
- erlc_params = +native -I $(rep_include) -o $(rep_ebin) $<
-else
- erlc_params = -I $(rep_include) -o $(rep_ebin) $<
-endif
-
+# It's possible to compile in native mode with :\r
+# $ make NATIVE=true\r
+ifdef NATIVE\r
+ erlc_params = +native -I $(rep_include) -I $(rep_include_yaws) -o $(rep_ebin) $<\r
+else\r
+ erlc_params = -I $(rep_include) -I $(rep_include_yaws) -o $(rep_ebin) $<\r
+endif\r
+\r
all: $(rep_ebin)/smtp.beam \\r
-$(rep_ebin)/euphorik_bd.beam \
-$(rep_ebin)/euphorik_minichat_conversation.beam \
-$(rep_ebin)/euphorik_requests.beam \
-$(rep_ebin)/euphorik_protocole.beam \
-$(rep_ebin)/euphorik_daemon.beam \
-$(rep_ebin)/euphorik_bd.beam \
-$(rep_ebin)/euphorik_bd_admin.beam \
-$(rep_ebin)/euphorik_common.beam \
-$(rep_ebin)/euphorik_test.beam
+$(rep_ebin)/euphorik_bd.beam \\r
+$(rep_ebin)/euphorik_minichat_conversation.beam \\r
+$(rep_ebin)/euphorik_requests.beam \\r
+$(rep_ebin)/euphorik_protocole.beam \\r
+$(rep_ebin)/euphorik_daemon.beam \\r
+$(rep_ebin)/euphorik_bd.beam \\r
+$(rep_ebin)/euphorik_bd_admin.beam \\r
+$(rep_ebin)/euphorik_common.beam \\r
+$(rep_ebin)/euphorik_test.beam\r
\r
$(rep_ebin)/smtp.beam: $(rep_erl)/smtp.erl\r
erlc $(erlc_params)\r
-
-$(rep_ebin)/euphorik_bd.beam: $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl
- erlc $(erlc_params)
-
-$(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)
-
-$(rep_ebin)/euphorik_minichat_conversation.beam: $(rep_erl)/euphorik_minichat_conversation.erl $(rep_include)/euphorik_bd.hrl
- erlc $(erlc_params)
-
-$(rep_ebin)/euphorik_requests.beam: $(rep_erl)/euphorik_requests.erl $(rep_include)/euphorik_defines.hrl
- erlc $(erlc_params)
-
-$(rep_ebin)/euphorik_protocole.beam: $(rep_erl)/euphorik_protocole.erl $(rep_include)/euphorik_defines.hrl
- erlc $(erlc_params)
-
-$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl
- erlc $(erlc_params)
-
-$(rep_ebin)/euphorik_common.beam: $(rep_erl)/euphorik_common.erl
- erlc $(erlc_params)
-
-$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_include)/euphorik_bd.hrl
- erlc $(erlc_params)
-
-clean:
- rm ebin/*.beam
+\r
+$(rep_ebin)/euphorik_bd.beam: $(rep_erl)/euphorik_bd.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_bd_admin.beam: $(rep_erl)/euphorik_bd_admin.erl $(rep_include)/euphorik_bd.hrl $(rep_include)/euphorik_defines.hrl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_minichat_conversation.beam: $(rep_erl)/euphorik_minichat_conversation.erl $(rep_include)/euphorik_bd.hrl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_requests.beam: $(rep_erl)/euphorik_requests.erl $(rep_include)/euphorik_defines.hrl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_protocole.beam: $(rep_erl)/euphorik_protocole.erl $(rep_include)/euphorik_defines.hrl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_daemon.beam: $(rep_erl)/euphorik_daemon.erl $(rep_include)/euphorik_defines.hrl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_common.beam: $(rep_erl)/euphorik_common.erl\r
+ erlc $(erlc_params)\r
+\r
+$(rep_ebin)/euphorik_test.beam: $(rep_erl)/euphorik_test.erl $(rep_include)/euphorik_bd.hrl\r
+ erlc $(erlc_params)\r
+\r
+clean:\r
+ rm ebin/*.beam\r
%\r
% You should have received a copy of the GNU General Public License\r
% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
-% \r
+%\r
% Ce module permet de gérer les données persistantes lié au site d'euphorik.ch.\r
% Il permet d'ajouter des message, de demande les messages sur une page donnée, etc..\r
% Ce module utilise une base mnesia.\r
\r
\r
-module(euphorik_bd).\r
--export([ \r
+-export([\r
% texte :\r
get_texte/1,\r
get_texte/2,\r
- \r
+\r
% users :\r
nouveau_user/2,\r
nouveau_user/4,\r
update_date_derniere_connexion/1,\r
update_ip/2,\r
update_pseudo_user/2,\r
- user_by_cookie/1, \r
- user_by_id/1, \r
+ user_by_cookie/1,\r
+ user_by_id/1,\r
user_by_login/1,\r
user_by_login_password/2,\r
user_by_mess/1,\r
css_from_user_cookie/1,\r
is_ek_master_from_cookie/1,\r
- \r
+\r
% messages :\r
nouveau_message/3,\r
nouveau_message_sys/1,\r
est_une_reponse_a_user/2,\r
a_repondu_a_message/2,\r
possede_message/2,\r
- \r
+\r
% ip :\r
list_ban/0,\r
ban/2,\r
deban/1,\r
est_banni/1,\r
can_register/1,\r
- \r
- % trolls :\r
- trolls/0,\r
- trolls/1,\r
- put_troll/2,\r
- mod_troll/2,\r
- del_troll/1,\r
- troll_by_id/1,\r
- current_troll/0,\r
- elire_troll/0,\r
- \r
+\r
% utiles :\r
- resultat_transaction/1,
+ resultat_transaction/1,\r
get_tuples/3 % must be in a transaction\r
]).\r
-import(qlc, [e/2, q/1, cursor/2]).\r
User\r
end,\r
resultat_transaction(mnesia:transaction(F)).\r
- \r
- \r
+\r
+\r
% Ajoute un nouveau user et le renvoie\r
nouveau_user(Login, Password, Cookie, Profile) ->\r
F = fun() ->\r
User\r
end,\r
resultat_transaction(mnesia:transaction(F)).\r
- \r
+\r
\r
% Définit les données du profile d'une utilisateur.\r
set_profile(Cookie, Login, Password, Profile) ->\r
mnesia:abort("update_ip: User inconnu")\r
end\r
end\r
- ). \r
- \r
- \r
+ ).\r
+\r
+\r
% Met à jour le pseudo du user\r
update_pseudo_user(UserId, Pseudo) ->\r
mnesia:transaction(\r
- fun() -> \r
+ fun() ->\r
case mnesia:wread({user, UserId}) of\r
[#user{profile = Profile} = User] when Profile#profile.pseudo =/= Pseudo ->\r
mnesia:write(User#user{profile = Profile#profile { pseudo = Pseudo } });\r
end\r
end\r
).\r
- \r
+\r
\r
% Est-ce qu'un utilisateur existe en fonction de son cookie ?\r
% Renvoie {ok, User} ou erreur\r
end\r
end\r
)).\r
- \r
- \r
+\r
+\r
user_by_id(ID) ->\r
resultat_transaction(mnesia:transaction(\r
fun() ->\r
end\r
end\r
)).\r
- \r
- \r
+\r
+\r
user_by_login(Login) ->\r
resultat_transaction(mnesia:transaction(\r
fun() ->\r
end\r
end\r
)).\r
- \r
+\r
\r
% Renvoie une chaine représentant le cookie ou undefined si pas trouvé.\r
css_from_user_cookie(Cookie) ->\r
- case user_by_cookie(Cookie) of \r
+ case user_by_cookie(Cookie) of\r
{ok, #user{profile = Profile}} ->\r
Profile#profile.css;\r
_ ->\r
undefined\r
end.\r
- \r
- \r
+\r
+\r
is_ek_master_from_cookie(Cookie) ->\r
case user_by_cookie(Cookie) of\r
{ok, #user{ek_master = true}} -> true;\r
_ -> false\r
end.\r
- \r
+\r
\r
user_by_login_password(Login, Password) ->\r
resultat_transaction(mnesia:transaction(\r
end\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Renvoie {ok, User} où User est un #user possédant le message donné.\r
user_by_mess(Id) ->\r
resultat_transaction(mnesia:transaction(\r
end\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Ajoute un message. Repond_A est une liste d'id auquel le message répond\r
% retourne soit l'id du message soit {erreur, <raison>}.\r
nouveau_message(Mess, Auteur_id, Repond_A_ids) ->\r
% regarde si les id 'Repond_A' existent\r
- F = fun() -> \r
+ F = fun() ->\r
Repond_a = lists:foldr(\r
fun(Repond_a_id, Acc) ->\r
- case mnesia:read({minichat, Repond_a_id}) of
+ case mnesia:read({minichat, Repond_a_id}) of\r
[M] -> [M | Acc];\r
- _ -> Acc % le message n'est pas trouvé
+ _ -> Acc % le message n'est pas trouvé\r
end\r
- end,
+ end,\r
[],\r
Repond_A_ids\r
),\r
Racine_id = case Repond_a of\r
[] -> undefined;\r
- [M | _] -> \r
+ [M | _] ->\r
Une_racine = M#minichat.racine_id,\r
% vérification que tout les messages de Repond_a possède la même racine (même conversation)\r
case lists:all(fun(R) -> R#minichat.racine_id =:= Une_racine end, Repond_a) of\r
_ ->\r
{erreur, "Les messages ne font pas partie de la même conversation"}\r
end\r
- end,
- if length(Repond_a) =/= length(Repond_A_ids) ->
- {erreur, "Un ou plusieurs messages introuvable"};
+ end,\r
+ if length(Repond_a) =/= length(Repond_A_ids) ->\r
+ {erreur, "Un ou plusieurs messages introuvable"};\r
true ->\r
case Racine_id of\r
{erreur, E} -> {erreur, E};\r
nouveau_message_sys("\"" ++ Profile#profile.pseudo ++ if Auteur#user.login =/= [] -> " (" ++ Auteur#user.login ++ ")"; true -> "" end ++ "\" est bloqué pour " ++ integer_to_list(trunc(?DUREE_BLOCAGE_SPAM / 1000)) ++ " secondes pour cause de flood.");\r
Auteur#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->\r
{erreur, "Bloqué pour cause de flood"};\r
- true -> \r
+ true ->\r
mnesia:write(Auteur_maj),\r
Id = nouvel_id(minichat),\r
inserer_reponses(Id, Repond_A_ids),\r
_ ->\r
{erreur, "L'auteur du message est introuvable"}\r
end\r
- end
+ end\r
end\r
end,\r
resultat_transaction(mnesia:transaction(F)).\r
- \r
+\r
% Définit Id_repondant comme étant la réponse à Ids. Ids est une liste d'id.\r
inserer_reponses(Id_repondant, [Id_mess | Reste]) ->\r
mnesia:write(#reponse_minichat{repondant = Id_repondant, cible = Id_mess}),\r
inserer_reponses(Id_repondant, Reste);\r
inserer_reponses(_, []) ->\r
ok.\r
- \r
- \r
+\r
+\r
% Permet de créer un message système.\r
% Renvoie l'id du message système\r
nouveau_message_sys(Mess) ->\r
Id\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Renvoie N messages se trouvant sur la première page\r
-messages(N) -> \r
+messages(N) ->\r
messages(N, 1).\r
\r
\r
-% Renvoie N messages se trouvant sur la page P
+% Renvoie N messages se trouvant sur la page P\r
% TODO FIXME : fonction en O(N * P) !\r
messages(N, P) ->\r
- F = fun() ->
- % % #minichat{contenu = contenu_message(E)}
+ F = fun() ->\r
get_tuples(minichat, mnesia:table_info(minichat, size) - N * P + 1, N)\r
end,\r
- resultat_transaction(mnesia:transaction(F)).
-
-
-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)
- ).
- \r
+ resultat_transaction(mnesia:transaction(F)).\r
+\r
+\r
+get_tuples(Table, First_id, N) ->\r
+ lists:foldr(\r
+ fun(Id, Acc) ->\r
+ case mnesia:read({Table, Id}) of\r
+ [T] -> [T | Acc];\r
+ _ -> Acc\r
+ end\r
+ end,\r
+ [],\r
+ lists:seq(First_id, First_id + N - 1)\r
+ ).\r
+\r
\r
% Renvoie les messages manquants pour la page P en sachant qu'il y a N message\r
% par page et que le dernier message que l'on possède est Id\r
messages(Id, N, P) ->\r
lists:filter(fun (M) -> M#minichat.id > Id end, messages(N, P)).\r
- \r
- \r
+\r
+\r
% Renvoie {ok, #minichat} (voir #minichat de euphorik_bd.hrl) à partir de son id.\r
message_by_id(Id) ->\r
resultat_transaction(mnesia:transaction(\r
fun() ->\r
case mnesia:read({minichat, Id}) of\r
- [M] -> {ok, M#minichat{contenu = contenu_message(M)}};\r
+ [M] -> {ok, M};\r
_ -> erreur\r
end\r
end\r
)).\r
- \r
- \r
-% Renvoie le contenu d'un message donnée en fonction du troll associé, à utiliser à l'intérieur d'une transaction.\r
-% TODO : Cette fonction pourrait être remplacée par un "outer-join", est-ce possible avec qlc ?\r
-contenu_message(E) ->\r
- case mnesia:index_read(troll, E#minichat.id, #troll.id_minichat) of\r
- [] -> E#minichat.contenu;\r
- [T] -> E#minichat.contenu ++ T#troll.content\r
- end.\r
- \r
\r
% Renvoie une liste de message (voir #minichat de euphorik_bd.hrl) à partir d'une liste d'id (Ids).\r
% TODO : optimisations ? serait-ce du O(n) ?\r
),[{tmpdir, ?KEY_SORT_TEMP_DIR}])\r
end\r
)).\r
- \r
+\r
\r
% Est-ce qu'un message existe ? Renvoie un boolean.\r
% TODO : ya pas plus simple ?\r
resultat_transaction(mnesia:transaction(fun() ->\r
length(e(q([E#minichat.id || E <- mnesia:table(minichat), E#minichat.id =:= Id]), [{tmpdir, ?KEY_SORT_TEMP_DIR}])) =:= 1\r
end)).\r
- \r
- \r
+\r
+\r
% Renvoie les reponses (utilisé normalement uniquement pendant le debug).\r
reponses() ->\r
F = fun() ->\r
e(q([E || E <- mnesia:table(reponse_minichat)]), [{tmpdir, ?KEY_SORT_TEMP_DIR}])\r
end,\r
resultat_transaction(mnesia:transaction(F)).\r
- \r
- \r
+\r
+\r
% Renvoie les messages auquel M_id répond.\r
parents(M_id) ->\r
resultat_transaction(mnesia:transaction(\r
M#minichat.id =:= R#reponse_minichat.cible]), [{tmpdir, ?KEY_SORT_TEMP_DIR}])\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Renvoie les message qui repondent à M_id\r
enfants(M_id) ->\r
resultat_transaction(mnesia:transaction(\r
M#minichat.id =:= R#reponse_minichat.repondant]), [{tmpdir, ?KEY_SORT_TEMP_DIR}])\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Renvoie les id des parents d'un message M (les messages auquels répond M)\r
% ordrés du plus petit au plus grand..\r
% On évite d'utiliser qlc pour des raisons de performance\r
fun(#reponse_minichat{cible = Cible}) -> Cible end,\r
Parents\r
));\r
- _ -> [] \r
+ _ -> []\r
end\r
end)).\r
- \r
- \r
+\r
+\r
% Renvoie les id des enfants d'un message M (les messages qui répondent à M)\r
% ordrés du plus petit au plus grand.\r
% @spec enfants_id(integer()) -> [integer()]\r
fun(#reponse_minichat{repondant = Repondant}) -> Repondant end,\r
Enfants\r
));\r
- _ -> [] \r
+ _ -> []\r
end\r
end)).\r
- \r
+\r
\r
% Est-ce que le message Id_mess est une réponse d'une message de Id_user ?\r
% On evite d'utiliser qlc (ce qui était fait avant) pour des raisons de performance.\r
end\r
)).\r
\r
- \r
+\r
% Est-ce que Id_user à répondu au message Id_mess\r
% On evite d'utiliser qlc (ce qui était fait avant) pour des raisons de performance.\r
a_repondu_a_message(Id_user, Id_mess) ->\r
end\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Est-ce que Id_user possède Id_mess ?\r
possede_message(Id_user, Id_mess) ->\r
case mnesia:transaction(\r
{atomic, [Id_user | []]} -> true;\r
_ -> false\r
end.\r
- \r
- \r
+\r
+\r
% renvoie la liste des ip bannies\r
% liste de {ip, temps_restant(en minutes), Users} ou Users est une liste de {pseudo, login}\r
% TODO : déterminer la complexité de cette fonction. (Il n'y a pas d'index sur #user.last_ip)\r
end\r
end\r
).\r
- \r
+\r
\r
% Débanni une ip\r
deban(IP) ->\r
ban(IP, 0).\r
\r
- \r
+\r
% Renvoie soit {true, Temps} où Temps est le temps en minutes pendant lequel le user est encore banni\r
% ou false.\r
est_banni(User_id) ->\r
end\r
end\r
)).\r
- \r
- \r
+\r
+\r
% Ban est une date tel que retourner par now().\r
% Ban_duration est un temps en minutes.\r
% retourne une date.\r
Duration_sec = Ban_duration * 60,\r
{MegaSec, Sec, MicroSec} = Ban,\r
{MegaSec + if Sec + Duration_sec >= 1000000 -> 1; true -> 0 end,(Sec + Duration_sec) rem 1000000, MicroSec}.\r
- \r
\r
-% Si deux enregistrements consequtifs de la même IP sont fait en moins d'une seconde alors \r
+\r
+% Si deux enregistrements consequtifs de la même IP sont fait en moins d'une seconde alors\r
% ip_table.nb_try_register est incrémenté de 1 sinon il est décrémenté de 1 (jusqu'a 0).\r
% Si ip_table.nb_try_register vaut 5 alors l'ip ne peux plus s'enregistrer pour une heure.\r
can_register(IP) ->\r
resultat_transaction(mnesia:transaction(\r
fun() ->\r
case e(q([I || I <- mnesia:table(ip_table), I#ip_table.ip =:= IP]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of\r
- [] -> \r
+ [] ->\r
mnesia:write(#ip_table{ip = IP, date_last_try_register = now()}),\r
true;\r
[T] ->\r
end\r
end\r
)).\r
- \r
-\r
-% Renvoie tous les trolls\r
-trolls() ->\r
- resultat_transaction(mnesia:transaction(\r
- fun() ->\r
- e(qlc:keysort(#troll.id, q([T || T <- mnesia:table(troll)])), [{tmpdir, ?KEY_SORT_TEMP_DIR}])\r
- end\r
- )).\r
- \r
- \r
-% Renvoie les trolls manquants posté après Last_id.\r
-trolls(Last_id) ->\r
- resultat_transaction(mnesia:transaction(\r
- fun() ->\r
- e(qlc:keysort(#troll.id, q([T || T <- mnesia:table(troll), T#troll.id > Last_id, T#troll.date_post =:= undefined])), [{tmpdir, ?KEY_SORT_TEMP_DIR}])\r
- end\r
- )).\r
- \r
- \r
- % Crée un nouveau troll.\r
- % Renvoie l'id du nouveau troll\r
- % ou max_troll_reached_per_user si le nombre de troll posté par l'utilisateur max a été atteind\r
- % ou max_troll_reached si le nombre de troll posté max a été atteind\r
- % ou user_unknown\r
-put_troll(User_id, Content) ->\r
- resultat_transaction(mnesia:transaction(\r
- fun() ->\r
- % control le nombre de troll déjà posté\r
- Nb_troll_poste_par_user = length(e(q(\r
- [\r
- E#troll.id || E <- mnesia:table(troll),\r
- E#troll.id_user =:= User_id,\r
- E#troll.date_post =:= undefined\r
- ]\r
- ), [{tmpdir, ?KEY_SORT_TEMP_DIR}])),\r
- Nb_troll_poste_total = length(e(q(\r
- [\r
- E#troll.id || E <- mnesia:table(troll),\r
- E#troll.date_post =:= undefined\r
- ]\r
- ), [{tmpdir, ?KEY_SORT_TEMP_DIR}])),\r
- User = user_by_id(User_id),\r
- case User of\r
- {ok, _} ->\r
- if Nb_troll_poste_par_user >= ?NB_MAX_TROLL_WAITING_BY_USER ->\r
- max_troll_reached_per_user;\r
- Nb_troll_poste_total >= ?NB_MAX_TROLL_WAITING ->\r
- max_troll_reached;\r
- true ->\r
- Id = nouvel_id(troll),\r
- mnesia:write(#troll{id = Id, id_user = User_id, date_create = now(), content = Content}),\r
- Id\r
- end;\r
- _ ->\r
- user_unknown\r
- end\r
- end\r
- )).\r
-\r
-\r
-% renvoie ok | erreur\r
-mod_troll(Troll_id, Content) ->\r
- mnesia:transaction(\r
- fun() ->\r
- case mnesia:wread({troll, Troll_id}) of\r
- [Troll = #troll{date_post = undefined}] ->\r
- mnesia:write(Troll#troll{content = Content});\r
- _ ->\r
- mnesia:abort("mod_troll: Troll inconnu ou déjà posté")\r
- end\r
- end\r
- ).\r
- \r
- \r
-del_troll(Troll_id) ->\r
- mnesia:transaction(\r
- fun() ->\r
- case mnesia:wread({troll, Troll_id}) of\r
- [#troll{date_post = undefined}] ->\r
- mnesia:delete({troll, Troll_id});\r
- _ ->\r
- mnesia:abort("mod_troll: Troll inconnu ou déjà posté")\r
- end\r
- end\r
- ).\r
- \r
- \r
-troll_by_id(Troll_id) ->\r
- resultat_transaction(mnesia:transaction(\r
- fun() ->\r
- case e(q([T || T <- mnesia:table(troll), T#troll.id =:= Troll_id]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of\r
- [T] -> {ok, T};\r
- _ ->\r
- erreur\r
- end\r
- end\r
- )).\r
- \r
-\r
-% Renvoie le troll actuel qui se trouve sur la page principale.\r
-% Renvois aucun si pas de troll courant.\r
-current_troll() ->\r
- resultat_transaction(mnesia:transaction(\r
- fun() ->\r
- C = cursor(qlc:keysort(#troll.date_post, q([T || T <- mnesia:table(troll), T#troll.date_post =/= undefined]), [{order, descending}]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]),\r
- R = case qlc:next_answers(C, 1) of\r
- [T] -> T;\r
- _ -> aucun\r
- end,\r
- qlc:delete_cursor(C),\r
- R\r
- end\r
- )).\r
\r
\r
-% Elit un troll au hasard parmis les trolls en attente (leur date_post =:= undefined)\r
-% Un message est posté par 'Sys' et le troll elu est lié à ce message\r
-% met à jour sa date de post.\r
-% renvoie plus_de_trolls si il n'y a aucun troll en attente.\r
-elire_troll() -> \r
- {A1,A2,A3} = now(),\r
- random:seed(A1, A2, A3),\r
- mnesia:transaction(\r
- fun() ->\r
- case e(q([T || T <- mnesia:table(troll), T#troll.date_post =:= undefined]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]) of\r
- [] ->\r
- plus_de_trolls;\r
- Trolls ->\r
- Troll = lists:nth(random:uniform(length(Trolls)), Trolls),\r
- Id_message = nouveau_message_sys("Troll de la semaine : "),\r
- Troll2 = Troll#troll{date_post = now(), id_minichat = Id_message},\r
- mnesia:write(Troll2)\r
- end\r
- end\r
- ).\r
- \r
- \r
% Renvoie le résultat d'une transaction (en décomposant le tuple fournit)\r
resultat_transaction({_, T}) ->\r
T.\r
% Renvoie un nouvel id pour une table donnée\r
nouvel_id(Table) ->\r
mnesia:dirty_update_counter(counter, Table, 1).\r
-
\ No newline at end of file
-% 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 <http://www.gnu.org/licenses/>.
-%
-% Module mettant à disposition tout un tas de fonction pour l'administration de la base de données euphorik comme :
-% - Création de la BD
-% - Mise à jour de la BD
-% - Backup et restauration
-% - Copie de la BD à partir d'un autre noeud
-%
-% @author G.Burri
-
-
--module(euphorik_bd_admin).
--export([
- version_bd/0,
- create/0,
- connect/0,
- connect/1,
- reset/0,
- update/0,
-
- backup/1,
- restore/1,
- change_node_name/4,
-
- toggle_ek_master/1,
- print_users/0,
- print_users/1,
- print_user/1
-]).
--import(qlc, [e/2, q/1, cursor/2]).
--include("../include/euphorik_bd.hrl").
--include("../include/euphorik_defines.hrl").
--include_lib("stdlib/include/qlc.hrl").
-
-
-% Renvoie la version courante de la BD.
-version_bd() ->
- euphorik_bd:resultat_transaction(mnesia:transaction(
- fun() ->
- mnesia:read({proprietes, version})
- end
- )).
-
-
-% Instructions pour créer une nouvelle base :
-% $erl -sname yaws -mnesia dir '"/projets/euphorik/BD"'
-% voir doc/installation.txt
-% >l(euphorik_bd).
-% >euphorik_bd:create().
-create() ->
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]), % nécessaire pour les tables sur disc
- mnesia:start(),
- create_tables(),
- reset().
-
-create_tables() ->
- mnesia:create_table(counter, [
- {attributes, record_info(fields, counter)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(proprietes, [
- {attributes, record_info(fields, proprietes)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(texte, [
- {attributes, record_info(fields, texte)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(minichat, [
- {type, ordered_set},
- {attributes, record_info(fields, minichat)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(reponse_minichat, [
- {type, bag},
- {attributes, record_info(fields, reponse_minichat)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(user, [
- {attributes, record_info(fields, user)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(ip_table, [
- {attributes, record_info(fields, ip_table)},
- {disc_copies, [node()]}
- ]),
- mnesia:create_table(troll, [
- {attributes, record_info(fields, troll)},
- {disc_copies, [node()]}
- ]),
- creer_indexes().
-
-
-% 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(reponse_minichat, cible),
- mnesia:add_table_index(user, cookie),
- mnesia:add_table_index(user, login),
+% coding: utf-8\r
+% Copyright 2008 Grégory Burri\r
+%\r
+% This file is part of Euphorik.\r
+%\r
+% Euphorik is free software: you can redistribute it and/or modify\r
+% it under the terms of the GNU General Public License as published by\r
+% the Free Software Foundation, either version 3 of the License, or\r
+% (at your option) any later version.\r
+%\r
+% Euphorik is distributed in the hope that it will be useful,\r
+% but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+% GNU General Public License for more details.\r
+%\r
+% You should have received a copy of the GNU General Public License\r
+% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
+%\r
+% Module mettant à disposition tout un tas de fonction pour l'administration de la base de données euphorik comme :\r
+% - Création de la BD\r
+% - Mise à jour de la BD\r
+% - Backup et restauration\r
+% - Copie de la BD à partir d'un autre noeud\r
+%\r
+% @author G.Burri\r
+\r
+\r
+-module(euphorik_bd_admin).\r
+-export([\r
+ version_bd/0,\r
+ create/0,\r
+ connect/0,\r
+ connect/1,\r
+ reset/0,\r
+ update/0,\r
+\r
+ backup/1,\r
+ restore/1,\r
+ change_node_name/4,\r
+\r
+ toggle_ek_master/1,\r
+ print_users/0,\r
+ print_users/1,\r
+ print_user/1\r
+]).\r
+-import(qlc, [e/2, q/1, cursor/2]).\r
+-include("../include/euphorik_bd.hrl").\r
+-include("../include/euphorik_defines.hrl").\r
+-include_lib("stdlib/include/qlc.hrl").\r
+\r
+\r
+% Renvoie la version courante de la BD.\r
+version_bd() ->\r
+ euphorik_bd:resultat_transaction(mnesia:transaction(\r
+ fun() ->\r
+ mnesia:read({proprietes, version})\r
+ end\r
+ )).\r
+\r
+\r
+% Instructions pour créer une nouvelle base :\r
+% $erl -sname yaws -mnesia dir '"/projets/euphorik/BD"'\r
+% voir doc/installation.txt\r
+% >l(euphorik_bd).\r
+% >euphorik_bd:create().\r
+create() ->\r
+ mnesia:stop(),\r
+ mnesia:delete_schema([node()]),\r
+ mnesia:create_schema([node()]), % nécessaire pour les tables sur disc\r
+ mnesia:start(),\r
+ create_tables(),\r
+ reset().\r
+\r
+create_tables() ->\r
+ mnesia:create_table(counter, [\r
+ {attributes, record_info(fields, counter)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ mnesia:create_table(proprietes, [\r
+ {attributes, record_info(fields, proprietes)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ mnesia:create_table(texte, [\r
+ {attributes, record_info(fields, texte)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ mnesia:create_table(minichat, [\r
+ {type, ordered_set},\r
+ {attributes, record_info(fields, minichat)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ mnesia:create_table(reponse_minichat, [\r
+ {type, bag},\r
+ {attributes, record_info(fields, reponse_minichat)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ mnesia:create_table(user, [\r
+ {attributes, record_info(fields, user)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ mnesia:create_table(ip_table, [\r
+ {attributes, record_info(fields, ip_table)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ % This table is not used anymore.\r
+ mnesia:create_table(troll, [\r
+ {attributes, record_info(fields, troll)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ creer_indexes().\r
+\r
+\r
+% mis à part car lors de la reprise de données avec load_textfile les indexes ne sont pas recréés\r
+creer_indexes() ->\r
+ % commence par supprimer les anciens indexes\r
+ lists:foreach(fun(T) ->\r
+ lists:foreach(fun(P) ->\r
+ mnesia:del_table_index(T, P)\r
+ end,\r
+ mnesia:table_info(T, index)\r
+ )\r
+ end,\r
+ ?TABLES\r
+ ),\r
+ mnesia:add_table_index(minichat, auteur_id),\r
+ mnesia:add_table_index(reponse_minichat, cible),\r
+ mnesia:add_table_index(user, cookie),\r
+ mnesia:add_table_index(user, login),\r
mnesia:add_table_index(troll, date_post),\r
- mnesia:add_table_index(troll, id_minichat).
-
-
-% Connexion à la base de données de yaws sur overnux
-connect() ->
- connect(yaws@flynux).
-connect(Node) ->
- mnesia:start(),
- mnesia:change_config(extra_db_nodes, [Node]).
-
-
-% Efface toutes les données de la base de données.
-reset() ->
- mnesia:clear_table(counter),
- mnesia:clear_table(proprietes),
- mnesia:clear_table(texte),
- mnesia:clear_table(user),
- mnesia:clear_table(reponse_minichat),
- mnesia:clear_table(minichat),
- mnesia:clear_table(troll),
- mnesia:clear_table(ip_table),
- % crée l'utilisateur root
- mnesia:transaction(fun() ->
- mnesia:write(#proprietes{nom = version, valeur = ?VERSION_BD}),
- User = #user{id = 0, profile = #profile{pseudo = "Sys"}, login = "Sys", date_creation = now(), date_derniere_connexion = now(), ek_master = true},
- mnesia:write(User),
- User
- end),
- peupler_texte().
-
-
-peupler_texte() ->
- mnesia:transaction(fun() ->
- mnesia:write(#texte{ id = 10, fr = "Login déjà existant"}),
- mnesia:write(#texte{ id = 20, fr = "Trop de register (flood)"}),
- mnesia:write(#texte{ id = 30, fr = "Couple login/pass introuvable"}),
- mnesia:write(#texte{ id = 40, fr = "Authentification impossible par cookie"}),
- mnesia:write(#texte{ id = 50, fr = "Impossible de mettre à jour le profile"}),
- mnesia:write(#texte{ id = 60, fr = "timeout"}),
- mnesia:write(#texte{ id = 70, fr = "Page inconnue"}),
- mnesia:write(#texte{ id = 80, fr = "Vous êtes banni pour encore ~s"}),
- mnesia:write(#texte{ id = 90, fr = "Message vide"}),
- mnesia:write(#texte{ id = 100, fr = "Impossible d'ajouter un nouveau message. Raison : ~s"}),
- mnesia:write(#texte{ id = 110, fr = "Utilisateur inconnu"}),
- mnesia:write(#texte{ id = 120, fr = "Il n'est pas possible de s'auto bannir"}),
- mnesia:write(#texte{ id = 130, fr = "L'utilisateur est lui même un ekMaster"}),
- mnesia:write(#texte{ id = 140, fr = "Utilisateur à bannir inconnu"}),
- mnesia:write(#texte{ id = 150, fr = "Utilisateur inconnu ou non ek master"}),
- mnesia:write(#texte{ id = 160, fr = "Utilisateur à slaper inconnu"}),
- mnesia:write(#texte{ id = 170, fr = "Utilisateur inconnu ou non ek master"}),
- mnesia:write(#texte{ id = 180, fr = "Le nombre de troll maximum par utilisateur est atteint : ~w "}),
- mnesia:write(#texte{ id = 190, fr = "Le nombre de troll maximum en attente est atteint : ~w "}),
- mnesia:write(#texte{ id = 200, fr = "Seul les ekMaster peuvent proposer des trolls"}),
- mnesia:write(#texte{ id = 210, fr = "Vous ne posséder pas ce troll"}),
- mnesia:write(#texte{ id = 220, fr = "Seul les ekMaster peuvent proposer des trolls"}),
- mnesia:write(#texte{ id = 230, fr = "Seul les ekMaster peuvent connaitre la liste des ips bannies"})
- end).
-
-
-% Met à jour la bd, compare ?VERSION_BD avec la version dans la table 'proprietes'
-% et exécute les patchs nécessaires.
-update() ->
- case mnesia:dirty_read({proprietes, version}) of
- [#proprietes{valeur = Version}] ->
- update(Version);
- _ ->
- erreur
- end.
-
-
-% Mise à jour de la BD.
-% attention : il est nécessaire de se trouver dans une transaction.
-update(?VERSION_BD) -> fini;
-update(Version) ->
- case mnesia:backup(fichier_backup(Version)) of
- ok ->
- case patch(Version) of
- ok ->
- mnesia:dirty_write(#proprietes{nom = version, valeur = Version + 1}),
- update(Version + 1);
- Erreur ->
- Erreur
- end;
- {error, Raison} -> {error, lists:flatten(io_lib:format("Erreur de création du backup de la version ~w : ~w", [Version, Raison]))}
- end.
-
-
-% Applique une modification de la BD pour passer d'une version à la suivante.
-% crée un backup avant l'application du patch
-% dans BD/backups nommé "backup<num>" où <num> et le numéro de la version.
-% 1 -> 2
+ mnesia:add_table_index(troll, id_minichat).\r
+\r
+\r
+% Connexion à la base de données de yaws sur overnux\r
+connect() ->\r
+ connect(yaws@flynux).\r
+connect(Node) ->\r
+ mnesia:start(),\r
+ mnesia:change_config(extra_db_nodes, [Node]).\r
+\r
+\r
+% Efface toutes les données de la base de données.\r
+reset() ->\r
+ mnesia:clear_table(counter),\r
+ mnesia:clear_table(proprietes),\r
+ mnesia:clear_table(texte),\r
+ mnesia:clear_table(user),\r
+ mnesia:clear_table(reponse_minichat),\r
+ mnesia:clear_table(minichat),\r
+ mnesia:clear_table(troll),\r
+ mnesia:clear_table(ip_table),\r
+ % crée l'utilisateur root\r
+ mnesia:transaction(fun() ->\r
+ mnesia:write(#proprietes{nom = version, valeur = ?VERSION_BD}),\r
+ User = #user{id = 0, profile = #profile{pseudo = "Sys"}, login = "Sys", date_creation = now(), date_derniere_connexion = now(), ek_master = true},\r
+ mnesia:write(User),\r
+ User\r
+ end),\r
+ peupler_texte().\r
+\r
+\r
+peupler_texte() ->\r
+ mnesia:transaction(fun() ->\r
+ mnesia:write(#texte{ id = 10, fr = "Login déjà existant"}),\r
+ mnesia:write(#texte{ id = 20, fr = "Trop de register (flood)"}),\r
+ mnesia:write(#texte{ id = 30, fr = "Couple login/pass introuvable"}),\r
+ mnesia:write(#texte{ id = 40, fr = "Authentification impossible par cookie"}),\r
+ mnesia:write(#texte{ id = 50, fr = "Impossible de mettre à jour le profile"}),\r
+ mnesia:write(#texte{ id = 60, fr = "timeout"}),\r
+ mnesia:write(#texte{ id = 70, fr = "Page inconnue"}),\r
+ mnesia:write(#texte{ id = 80, fr = "Vous êtes banni pour encore ~s"}),\r
+ mnesia:write(#texte{ id = 90, fr = "Message vide"}),\r
+ mnesia:write(#texte{ id = 100, fr = "Impossible d'ajouter un nouveau message. Raison : ~s"}),\r
+ mnesia:write(#texte{ id = 110, fr = "Utilisateur inconnu"}),\r
+ mnesia:write(#texte{ id = 120, fr = "Il n'est pas possible de s'auto bannir"}),\r
+ mnesia:write(#texte{ id = 130, fr = "L'utilisateur est lui même un ekMaster"}),\r
+ mnesia:write(#texte{ id = 140, fr = "Utilisateur à bannir inconnu"}),\r
+ mnesia:write(#texte{ id = 150, fr = "Utilisateur inconnu ou non ek master"}),\r
+ mnesia:write(#texte{ id = 160, fr = "Utilisateur à slaper inconnu"}),\r
+ mnesia:write(#texte{ id = 170, fr = "Utilisateur inconnu ou non ek master"}),\r
+ mnesia:write(#texte{ id = 230, fr = "Seul les ekMaster peuvent connaitre la liste des ips bannies"})\r
+ end).\r
+\r
+\r
+% Met à jour la bd, compare ?VERSION_BD avec la version dans la table 'proprietes'\r
+% et exécute les patchs nécessaires.\r
+update() ->\r
+ case mnesia:dirty_read({proprietes, version}) of\r
+ [#proprietes{valeur = Version}] ->\r
+ update(Version);\r
+ _ ->\r
+ erreur\r
+ end.\r
+\r
+\r
+% Mise à jour de la BD.\r
+% attention : il est nécessaire de se trouver dans une transaction.\r
+update(?VERSION_BD) -> fini;\r
+update(Version) ->\r
+ case mnesia:backup(fichier_backup(Version)) of\r
+ ok ->\r
+ case patch(Version) of\r
+ ok ->\r
+ mnesia:dirty_write(#proprietes{nom = version, valeur = Version + 1}),\r
+ update(Version + 1);\r
+ Erreur ->\r
+ Erreur\r
+ end;\r
+ {error, Raison} -> {error, lists:flatten(io_lib:format("Erreur de création du backup de la version ~w : ~w", [Version, Raison]))}\r
+ end.\r
+\r
+\r
+% Applique une modification de la BD pour passer d'une version à la suivante.\r
+% crée un backup avant l'application du patch\r
+% dans BD/backups nommé "backup<num>" où <num> et le numéro de la version.\r
+% 1 -> 2\r
patch(1) ->\r
% Prend un chemin vers la feuille de style de type "css/1/euphorik.css"\r
% et renvoie "styles/1/euphorik.css"\r
- Transforme_css = fun("css" ++ Reste) ->
+ Transforme_css = fun("css" ++ Reste) ->\r
"styles" ++ Reste;\r
(F) -> F\r
end,\r
)\r
end,\r
F(F, M)\r
- end,
+ end,\r
% Prend un chemin vers la feuille de style de type "css/1/euphorik.css"\r
% et renvoie "styles/1/euphorik.css"\r
- Transforme_css = fun("css" ++ Reste) ->
+ Transforme_css = fun("css" ++ Reste) ->\r
"styles" ++ Reste;\r
(F) -> F\r
end,\r
)\r
end,\r
F(F, M)\r
- end,
- mnesia:create_table(texte, [
- {attributes, record_info(fields, texte)},
- {disc_copies, [node()]}
- ]),
- peupler_texte(),
- % traitement des users
- 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, 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)
- ),
- 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)
- ),
- 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) -> Traiter_message(M, M#minichat.id) end, Messages)
- end
- ) of
- {aborted, Raison} -> {erreur, Raison};
- {atomic, _} -> ok
+ end,\r
+ mnesia:create_table(texte, [\r
+ {attributes, record_info(fields, texte)},\r
+ {disc_copies, [node()]}\r
+ ]),\r
+ peupler_texte(),\r
+ % traitement des users\r
+ mnesia:transform_table(\r
+ user,\r
+ 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}) ->\r
+ {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}\r
+ end,\r
+ record_info(fields, user)\r
+ ),\r
+ mnesia:transform_table(\r
+ minichat,\r
+ fun({minichat, Id, Auteur_id, Date, Pseudo, Contenu, Troll_id}) ->\r
+ {minichat, Id, Auteur_id, Date, Pseudo, Contenu, Troll_id, Id}\r
+ end,\r
+ record_info(fields, minichat)\r
+ ),\r
+ case mnesia:transaction(\r
+ fun() ->\r
+ % met à jour les enfants des racines\r
+ % 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..\r
+ Messages = e(q([M || M <- mnesia:table(minichat), euphorik_bd:parents(M#minichat.id) =:= []]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]),\r
+ lists:foreach(fun(M) -> Traiter_message(M, M#minichat.id) end, Messages)\r
+ end\r
+ ) of\r
+ {aborted, Raison} -> {erreur, Raison};\r
+ {atomic, _} -> ok\r
end;\r
% 2 -> 3\r
patch(2) ->\r
{minichat, Id, Auteur_id, Date, Pseudo, Contenu, Racine_id, normal}\r
end,\r
record_info(fields, minichat)\r
- ),
- 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)})
+ ),\r
+ mnesia:transaction(fun() ->\r
+ % comble les trous entre les id non-contigues\r
+ lists:foreach(fun(Id) ->\r
+ case mnesia:read({minichat, Id}) of\r
+ [] ->\r
+ {ok, #user{profile = Profile}} = euphorik_bd:user_by_id(0),\r
+ mnesia:write(#minichat{id = Id, auteur_id = 0, date = undefined, pseudo = Profile#profile.pseudo, contenu = "Comblement...", racine_id = Id, status = deleted});\r
+ _ -> rien\r
+ end\r
+ end,\r
+ lists:seq(1, mnesia:table_info(minichat, size))\r
+ ),\r
+ % la table troll utilise maintenant son index et pas celui de la table minichat (correction d'un vieux bug)\r
+ mnesia:write(#counter{key = troll, value = mnesia:table_info(minichat, size)})\r
end),\r
- 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.
-dossier_backups() ->
- mnesia:system_info(directory) ++ "/backups/".
-
-
-% 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).
-\r
-
-% 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}]).
-
-
-% 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).
-
-
-% 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) ->
- euphorik_bd:resultat_transaction(mnesia:transaction(
- fun() ->
- Users = e(q([E || E <- mnesia:table(user), E#user.id =:= User_id]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]),
- case Users of
- [User] ->
- mnesia:write(User#user{ek_master = not User#user.ek_master});
- _ -> erreur
- end
- end
- )).
-
-
-% Affiche N user trié par leur date de dernière connexion.
-% Opt est une liste d'option d'affichage :
-% * ekmaster : n'affiche que les admins
-print_users(N, Opt) ->
- AfficheQueLesEkMaster = lists:any(fun(O) -> O =:= ekmaster end, Opt),
- euphorik_bd:resultat_transaction(mnesia:transaction(fun() ->
- C = cursor(
- qlc:keysort(
- #user.date_derniere_connexion,
- if AfficheQueLesEkMaster ->
- q([E || E <- mnesia:table(user), E#user.ek_master =:= true]);
- true ->
- q([E || E <- mnesia:table(user)])
- end,
- [{order, descending}]
- ),
- [{tmpdir, ?KEY_SORT_TEMP_DIR}]
- ),
- Users = qlc:next_answers(C, N),
- lists:foreach(
- fun(U) ->
- print_user(U)
- end,
- Users
- ),
- qlc:delete_cursor(C)
- end)).
-
-
-% Affiche tous les users.
-print_users(Opt) ->
- print_users(all_remaining, Opt).
-
-% Affiche tous les users.
-print_users() ->
- print_users(all_remaining, []).
-
-print_user(User) when is_record(User, user) ->
- #user{id = Id, profile = #profile{pseudo = Pseudo}, login = Login, ek_master = Ek_master, date_derniere_connexion = Date, last_ip = IP} = User,
- {{Annee, Mois, Jour}, {Heure, Min, _}} = calendar:now_to_local_time(Date),
- io:format(
- % id pseudo (login) IP Jour Mois Année Heure Minute
- "~4w : ~10.10..s(~10.10..s) ~s ~2w.~2.2.0w.~w - ~2wh~2.2.0w~n",
- [
- Id,
- if Ek_master -> "*"; true -> "" end ++ Pseudo,
- Login,
- euphorik_common:serialize_ip(IP),
- Jour, Mois, Annee, Heure, Min
- ]
- );
-% Affichage d'un user en fonction de son login
-print_user(Login) when is_list(Login) ->
- case euphorik_bd:user_by_login(Login) of
- {ok, User} ->
- print_user(User);
- _ ->
- {erreur, "Login pas trouvé : " ++ Login}
- end;
-% Affichage d'un user en fonction de son id
-print_user(Id) when is_integer(Id) ->
- case euphorik_bd:user_by_id(Id) of
- {ok, User} ->
- print_user(User);
- _ ->
- {erreur, "Id pas trouvé : " ++ integer_to_list(Id)}
- end.
-
+ creer_indexes(). % uniquement pour l'indice sur id_minichat de la table troll\r
+\r
+\r
+% Renvoie le dossier dans lequel les backups sont effectué, ce dossier doit être en écriture.\r
+dossier_backups() ->\r
+ mnesia:system_info(directory) ++ "/backups/".\r
+\r
+\r
+% Renvoie le fichier (avec le chemin) correspondant à la version Version, par exemple : "/var/euphorik/BD/backups/backup1"\r
+fichier_backup(Version) when is_integer(Version) ->\r
+ dossier_backups() ++ "backup" ++ integer_to_list(Version).\r
+\r
+\r
+% crée un backup dont le nom est fournit dans le repertoire backups qui se trouve dans le repertoire de la BD.\r
+backup(Fichier) ->\r
+ mnesia:backup(dossier_backups() ++ Fichier).\r
+\r
+\r
+% Restaure un backup de la BD.\r
+restore(Fichier) when is_list(Fichier) ->\r
+ mnesia:restore(dossier_backups() ++ Fichier, []);\r
+% Reviens à une version précédente de la base de données.\r
+% (les données insérées durant les versions plus récentes sont perdues).\r
+restore(Version) when is_integer(Version) ->\r
+ mnesia:restore(fichier_backup(Version), []). % [{default_op, recreate_tables}]).\r
+\r
+\r
+% Change le nom du noeud d'un backup.\r
+% provient d'ici : http://www.erlang.org/doc/apps/mnesia/Mnesia_chap7.html#6.9\r
+% From : l'ancien nom\r
+% To : le nouveau nom\r
+% Source : le nom du fichier de backup\r
+% Target : le nom du fichier du nouveau backup\r
+change_node_name(From, To, Source, Target) ->\r
+ Switch =\r
+ fun(Node) when Node == From -> To;\r
+ (Node) when Node == To -> throw({error, already_exists});\r
+ (Node) -> Node\r
+ end,\r
+ Convert =\r
+ fun({schema, db_nodes, Nodes}, Acc) ->\r
+ {[{schema, db_nodes, lists:map(Switch,Nodes)}], Acc};\r
+ ({schema, version, Version}, Acc) ->\r
+ {[{schema, version, Version}], Acc};\r
+ ({schema, cookie, Cookie}, Acc) ->\r
+ {[{schema, cookie, Cookie}], Acc};\r
+ ({schema, Tab, CreateList}, Acc) ->\r
+ Keys = [ram_copies, disc_copies, disc_only_copies],\r
+ OptSwitch =\r
+ fun({Key, Val}) ->\r
+ case lists:member(Key, Keys) of\r
+ true -> {Key, lists:map(Switch, Val)};\r
+ false-> {Key, Val}\r
+ end\r
+ end,\r
+ {[{schema, Tab, lists:map(OptSwitch, CreateList)}], Acc};\r
+ (Other, Acc) ->\r
+ {[Other], Acc}\r
+ end,\r
+ mnesia:traverse_backup(Source, Target, Convert, switched).\r
+\r
+\r
+% Obsolète\r
+%~ backup_text(File) ->\r
+ %~ mnesia:dump_to_textfile(File).\r
+%~ restore_text(File) ->\r
+ %~ mnesia:stop(),\r
+ %~ mnesia:delete_schema([node()]),\r
+ %~ mnesia:start(),\r
+ %~ create_tables(),\r
+ %~ case mnesia:load_textfile(File) of\r
+ %~ {atomic, ok} ->\r
+ %~ update(),\r
+ %~ creer_indexes();\r
+ %~ Erreur ->\r
+ %~ Erreur\r
+ %~ end.\r
+\r
+\r
+toggle_ek_master(User_id) ->\r
+ euphorik_bd:resultat_transaction(mnesia:transaction(\r
+ fun() ->\r
+ Users = e(q([E || E <- mnesia:table(user), E#user.id =:= User_id]), [{tmpdir, ?KEY_SORT_TEMP_DIR}]),\r
+ case Users of\r
+ [User] ->\r
+ mnesia:write(User#user{ek_master = not User#user.ek_master});\r
+ _ -> erreur\r
+ end\r
+ end\r
+ )).\r
+\r
+\r
+% Affiche N user trié par leur date de dernière connexion.\r
+% Opt est une liste d'option d'affichage :\r
+% * ekmaster : n'affiche que les admins\r
+print_users(N, Opt) ->\r
+ AfficheQueLesEkMaster = lists:any(fun(O) -> O =:= ekmaster end, Opt),\r
+ euphorik_bd:resultat_transaction(mnesia:transaction(fun() ->\r
+ C = cursor(\r
+ qlc:keysort(\r
+ #user.date_derniere_connexion,\r
+ if AfficheQueLesEkMaster ->\r
+ q([E || E <- mnesia:table(user), E#user.ek_master =:= true]);\r
+ true ->\r
+ q([E || E <- mnesia:table(user)])\r
+ end,\r
+ [{order, descending}]\r
+ ),\r
+ [{tmpdir, ?KEY_SORT_TEMP_DIR}]\r
+ ),\r
+ Users = qlc:next_answers(C, N),\r
+ lists:foreach(\r
+ fun(U) ->\r
+ print_user(U)\r
+ end,\r
+ Users\r
+ ),\r
+ qlc:delete_cursor(C)\r
+ end)).\r
+\r
+\r
+% Affiche tous les users.\r
+print_users(Opt) ->\r
+ print_users(all_remaining, Opt).\r
+\r
+% Affiche tous les users.\r
+print_users() ->\r
+ print_users(all_remaining, []).\r
+\r
+print_user(User) when is_record(User, user) ->\r
+ #user{id = Id, profile = #profile{pseudo = Pseudo}, login = Login, ek_master = Ek_master, date_derniere_connexion = Date, last_ip = IP} = User,\r
+ {{Annee, Mois, Jour}, {Heure, Min, _}} = calendar:now_to_local_time(Date),\r
+ io:format(\r
+ % id pseudo (login) IP Jour Mois Année Heure Minute\r
+ "~4w : ~10.10..s(~10.10..s) ~s ~2w.~2.2.0w.~w - ~2wh~2.2.0w~n",\r
+ [\r
+ Id,\r
+ if Ek_master -> "*"; true -> "" end ++ Pseudo,\r
+ Login,\r
+ euphorik_common:serialize_ip(IP),\r
+ Jour, Mois, Annee, Heure, Min\r
+ ]\r
+ );\r
+% Affichage d'un user en fonction de son login\r
+print_user(Login) when is_list(Login) ->\r
+ case euphorik_bd:user_by_login(Login) of\r
+ {ok, User} ->\r
+ print_user(User);\r
+ _ ->\r
+ {erreur, "Login pas trouvé : " ++ Login}\r
+ end;\r
+% Affichage d'un user en fonction de son id\r
+print_user(Id) when is_integer(Id) ->\r
+ case euphorik_bd:user_by_id(Id) of\r
+ {ok, User} ->\r
+ print_user(User);\r
+ _ ->\r
+ {erreur, "Id pas trouvé : " ++ integer_to_list(Id)}\r
+ end.\r
+\r
%
% You should have received a copy of the GNU General Public License
% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
-%
-% Module avec plein de bordel utile à l'intérieur.
+%
+% Module with some useful stuffs.
% @author G.Burri
Pos when Pos > 0 -> T + 1;
_ -> T
end.
-
+
% Retourne la difference entre deux timestamp (erlang:now()) en miliseconde
delta_date_ms(D1, D2) ->
% Retourne la différence entre deux timestamp (erlang:now) en minutes
delta_date_minute(D1, D2) ->
trunc(delta_date_ms(D1, D2) / 1000 / 60).
-
+
serialize_ip(undefined) ->
"<unknown IP>";
serialize_ip(IP) ->
lists:flatten(io_lib:format("~w.~w.~w.~w", tuple_to_list(IP))).
-
-
+
+
unserialize_ip(IP) ->
case io_lib:fread("~d.~d.~d.~d", IP) of
{ok, [A, B, C, D], []} -> {A, B, C, D};
%\r
% You should have received a copy of the GNU General Public License\r
% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
-% \r
+%\r
% Module tournant en background s'occupant periodiquement de certaines tâches :\r
-% - sélection du prochain troll chaque semaine\r
% - rechargement des modules lors d'une mise en production\r
% Date : 05.11.2007\r
% @author G.Burri\r
start(_A) ->\r
register(euphorik_daemon, self()),\r
loop().\r
- \r
- \r
+\r
+\r
loop() ->\r
- % on attend une minute de plus pour prevenir une dérive négative (ce qui pourrait engendrer une double élection)\r
receive\r
switch -> % permet de substituer le code du process par un nouveau code, voir reload_euphorik\r
- euphorik_daemon:loop() \r
- after 1000 * (trunc(temps_prochaine_election() + 60)) ->\r
- euphorik_bd:elire_troll(),\r
euphorik_daemon:loop()\r
end.\r
\r
- \r
-% Renvoie le nombre de seconde qu'il reste jusque au prochain lundi à l'heure donnée (l'heure est sur 24heures)\r
-% 86400 est le nombre de seconde dans un jour\r
-temps_prochaine_election() ->\r
- {Date, {H,M,S}} = calendar:local_time(),\r
- Delta = (?JOUR_ELECTION_TROLL - 1) * 86400 + ?HEURE_ELECTION_TROLL * 60 * 60\r
- -((calendar:day_of_the_week(Date) - 1) * 86400 + H * 60 * 60 + M * 60 + S),\r
- % attention au cas où deux dates (maintenant et la date d'élection) ne se trouvent pas dans la même semaine.\r
- if Delta =< 0 -> Delta + 7 * 86400; true -> Delta end.\r
-\r
-\r
% Recharge tous les modules euphorik.\r
% Appelé lors d'une mise en prod.\r
% TODO : récupérer les noms à partir des .beam dans /modules/ebin\r
% changement du code du daemon\r
euphorik_daemon ! switch,\r
ok.\r
-
\ No newline at end of file
%\r
% You should have received a copy of the GNU General Public License\r
% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
-% \r
+%\r
% Ce module permet la gestion des conversations du minichat d'euphorik.\r
% Un message (enfant) peut répondre à des messages (ses parents).\r
% Un message (parent) peut avoir plusieurs réponses (enfants)\r
% @author G.Burri\r
-% \r
+%\r
% Les conversation se compose d'une liste de tuple comprenant la conversation, du premier message de la conversation,\r
% et d'un booleen indiquant s'il y a encore des messages\r
% @type Conversations() = [{Conversation(), Message(), bool()}]\r
-% \r
+%\r
% Une conversation est simplement une liste de messages\r
% @type Conversation() = [Message()]\r
%\r
% Un message est un tuple représentant le message et la liste des id\r
% des messages auquels il répond\r
% @type Message() = {#minichat, [int()]}\r
-
+\r
\r
-module(euphorik_minichat_conversation).\r
-export([\r
-import(lists, [reverse/1, any/2, map/2, sublist/3, filter/2]).\r
-import(euphorik_bd, [resultat_transaction/1]).\r
-import(mnesia, [table/1, transaction/1]).\r
- \r
- \r
+\r
+\r
% Renvoie les conversations.\r
% Chaque racine est un tuple {R, P, D}\r
% R : l'id de la racine\r
true ->\r
mise_en_forme_conversations(Conversations)\r
end.\r
- \r
+\r
\r
% Mise en forme des conversations pour l'utilisateur du module.\r
% @type Conversation_principale() = {[integer()], bool}\r
mise_en_forme_conversations([]) -> [];\r
mise_en_forme_conversations([{Principale, Plus_principale} | Conversations]) ->\r
[{mise_en_forme_conversation(Principale), Plus_principale} | map(fun({_, Cn, _, Plus}) -> {mise_en_forme_conversation(Cn), Plus} end, Conversations)].\r
- \r
- \r
+\r
+\r
% Mise en forme d'une liste d'id de messages : [4, 9, 8, ...] -> [{#minichat, [5, 6]}, ...].\r
% Ajoute les parents de chaque message.\r
% @spec mise_en_forme_conversation([integer()]) -> [{#minichat, [integer()]}]\r
end\r
)).\r
\r
- \r
+\r
% Renvoie une liste de conversations, le première élément correspond à la conversation principale.\r
% Les autres éléments sont des tuples {C, Cn, X, Plus}, voir conversation/4 pour plus d'infos.\r
% Racines est une liste de tuple {Id, P} des racines des conversations ou P est la page et Id l'id du message.\r
% @spec conversations_detailees([{integer(), integer()}], integer(), integer(), integer()) -> [[{integer(), bool()}] | Conversation_detailee()]\r
-conversations_detailees(Racines, N, D, P) -> \r
+conversations_detailees(Racines, N, D, P) ->\r
Conversations = map(fun({Racine, P_conv, Dernier}) -> conversation(Racine, N, Dernier, P_conv) end, Racines),\r
- Conversation_principale = resultat_transaction(transaction(fun() ->
+ Conversation_principale = resultat_transaction(transaction(fun() ->\r
Dernier_id = mnesia:table_info(minichat, size),\r
{CP, Plus} = conversation_principale(Dernier_id, Conversations, N, P),\r
{[M || M <- CP, M > D], Plus} % filtre en fonction de D\r
end)),\r
[Conversation_principale | Conversations].\r
- \r
+\r
\r
% Construit la conversation principale en fonction d'un id de message initialement placé sur le dernier message\r
% et la liste de conversations.\r
end,\r
Plus\r
}.\r
- \r
- \r
+\r
+\r
% Id est l'id d'un message, voir ce dessus\r
% 'Messages' sont les messages que l'on doit enlever de la conversation\r
% S est le nombre de messages qu'il faut sauter.\r
% @spec conversation_principale2(integer(), [integer()], integer(), integer()) -> [integer()]\r
conversation_principale2(_, _, 0, _) ->\r
- [];
+ [];\r
conversation_principale2(0, _, _, _) ->\r
[];\r
-conversation_principale2(Id, Messages, N, S) ->
+conversation_principale2(Id, Messages, N, S) ->\r
% traitement message par message (pas des plus performant :/)\r
Doit_etre_saute = any(fun(E) -> E == Id end, Messages),\r
- if Doit_etre_saute -> \r
+ if Doit_etre_saute ->\r
conversation_principale2(Id - 1, Messages, N, S); % le message ne fait pas partie de la conversation\r
S =:= 0 ->\r
[Id | conversation_principale2(Id - 1, Messages, N - 1, S)]; % ok : le message fait partie de la conversation\r
true ->\r
conversation_principale2(Id - 1, Messages, N, S - 1) % on n'a pas encore atteint le début de la page\r
end.\r
- \r
- \r
+\r
+\r
% Renvoie un tuple {C, Cn, X, Plus} où\r
% C : La conversation complète\r
% Cn : La conversation tronqué en fonction de N, D et P\r
)\r
end,\r
reverse(X),\r
- Decalage + N - 1 < length(C) \r
+ Decalage + N - 1 < length(C)\r
}.\r
- \r
- \r
+\r
+\r
% Renvoie un tuple {C, X} où C est la conversation complète et X les messages répondant à des mess qui ne font pas partie de la conversation\r
% Attention : les messages de C et de X sont ordrés du plus grand Id au plus petit.\r
% @spec conversation([integer()], [integer()], [integer()]) -> {[int()], [int()]}\r
end;\r
conversation(Messages, [], X) ->\r
{Messages, X}.\r
- \r
+\r
\r
% Intersection entre deux listes : [1, 3, 4] n [2, 4, 7] = [4]\r
% @spec intersection(list(term()), list(term())) -> list(term())\r
%\r
% You should have received a copy of the GNU General Public License\r
% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
-% \r
+%\r
% Ce module gére les différents messages envoyés par le client (javascript) via AJAX.\r
% Les messages donnés ainsi que les réponses sont au format JSON.\r
% @author G.Burri\r
put_message/1,\r
ban/1,\r
slap/1,\r
- put_troll/1,\r
- mod_troll/1,\r
- del_troll/1,\r
unban_ip/1,\r
list_banned_ips/1,\r
erreur/1\r
erreur_register_flood()\r
end;\r
% Enregistrement sans {Login, Password}\r
-register([{profile, Profile_json}], IP) -> \r
+register([{profile, Profile_json}], IP) ->\r
Can_register = euphorik_bd:can_register(IP),\r
if Can_register ->\r
Profile = profile_from_json(Profile_json),\r
true ->\r
erreur_register_flood()\r
end.\r
- \r
+\r
erreur_register_flood() ->\r
erreur(20).\r
- \r
+\r
\r
% Un utilisateur se logge (avec un couple {login, mot de passe})\r
login([{login, Login}, {password, Password}], IP) ->\r
case euphorik_bd:user_by_login_password(Login, Password) of\r
{ok, User} ->\r
loginUser(User, IP);\r
- _ -> \r
+ _ ->\r
timer:sleep(?TEMPS_ATTENTE_ERREUR_LOGIN),\r
erreur(30)\r
end;\r
timer:sleep(?TEMPS_ATTENTE_ERREUR_LOGIN),\r
erreur(40)\r
end.\r
- \r
- \r
+\r
+\r
% L'utilisateur donné se logge avec l'ip donnée.\r
loginUser(User, IP) ->\r
euphorik_bd:update_ip(User#user.id, IP),\r
euphorik_bd:update_date_derniere_connexion(User#user.id),\r
json_reponse_login_ok(User).\r
- \r
- \r
+\r
+\r
% Renvoie un string() représentant un cookie en base 36. Il y a 10^32 possibillités.\r
generer_cookie() ->\r
{A1, A2, A3} = now(),\r
Chat_order_valide = lists:any(fun(E) -> E =:= Chat_order end, [reverse, chrono]),\r
if not Chat_order_valide ->\r
{erreur, Chat_order_str ++ " n'est pas une valeur acceptée pour 'chat_order'"};\r
- true -> \r
+ true ->\r
Nick_format = list_to_atom(Nick_format_str),\r
Nick_format_valide = lists:any(fun(E) -> E =:= Nick_format end, [nick, login, nick_login]),\r
if not Nick_format_valide ->\r
{erreur, Nick_format_str ++ " n'est pas une valeur acceptée pour 'nick_format'"};\r
- true -> \r
+ true ->\r
Ostentatious_master = list_to_atom(Ostentatious_master_str),\r
Ostentatious_master_valide = lists:any(fun(E) -> E =:= Ostentatious_master end, [invisible, light, heavy]),\r
if not Ostentatious_master_valide ->\r
ostentatious_master = Ostentatious_master\r
}\r
end\r
- end \r
+ end\r
end.\r
\r
\r
Last_message_id = case lists:keysearch(last_message_id, 1, Data) of {value, {_, Id}} -> Id; _ -> 0 end,\r
{value, {_, Message_count}} = lists:keysearch(message_count, 1, Data),\r
Main_page = case lists:keysearch(main_page, 1, Data) of {value, {_, P}} -> P; _ -> 1 end,\r
- Troll_id = case lists:keysearch(troll_id, 1, Data) of {value, {_, T}} -> T; _ -> 0 end,\r
{value, {_, {array, Conversations_json}}} = lists:keysearch(conversations, 1, Data),\r
Racines_conversations = lists:map(\r
fun({struct, [{root, Racine}, {page, Page} | Reste]}) ->\r
{ok, U} -> U;\r
_ -> inconnu\r
end,\r
- case {mnesia:subscribe({table, minichat, detailed}), mnesia:subscribe({table, troll, detailed})} of\r
- {{error, E}, _} -> E;\r
- {_, {error, E}} -> E;\r
+ case mnesia:subscribe({table, minichat, detailed}) of\r
+ {error, E} -> E;\r
_ ->\r
% attente d'événements\r
- R = wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id, Main_page, Troll_id),\r
+ R = wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id, Main_page),\r
mnesia:unsubscribe({table, minichat, detailed}),\r
- mnesia:unsubscribe({table, troll, detailed}),\r
R\r
end;\r
% Attend un événement pour la page "Admin"\r
-wait_event([{page, "admin"}, {last_troll, Last_troll}]) ->\r
- case wait_event_page_admin(Last_troll) of\r
+wait_event([{page, "admin"}]) ->\r
+ case wait_event_page_admin() of\r
banned_ips_refresh ->\r
- {struct, \r
- [\r
- {reply, "banned_ips_refresh"}\r
- ]\r
- };\r
- {mod, Troll} ->\r
{struct,\r
[\r
- {reply, "troll_modified"},\r
- {troll_id, Troll#troll.id},\r
- {content, Troll#troll.content}\r
+ {reply, "banned_ips_refresh"}\r
]\r
};\r
- {add, Trolls} ->\r
- {struct,\r
- [\r
- {reply, "troll_added"},\r
- {trolls, {array, \r
- lists:map(\r
- fun(T) -> \r
- {ok, #user{profile = Profile} = User} = euphorik_bd:user_by_id(T#troll.id_user),\r
- {struct,\r
- [\r
- {troll_id, T#troll.id},\r
- {content, T#troll.content},\r
- {author, Profile#profile.pseudo},\r
- {author_id, User#user.id}\r
- ]\r
- }\r
- end,\r
- Trolls\r
- )\r
- }}\r
- ]\r
- }; \r
- {del, Troll_id} ->\r
- {struct,\r
- [\r
- {reply, "troll_deleted"},\r
- {troll_id, Troll_id}\r
- ]\r
- }; \r
_ ->\r
erreur(60)\r
end;\r
erreur(70).\r
\r
\r
-% Attend un événement pour la page "Chat" et renvoie soit un troll soit les messages manquants au client.\r
-wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id, Main_page, Troll_id) ->\r
- % est-ce que le troll est à jour ?\r
- case euphorik_bd:current_troll() of\r
- Current when is_record(Current, troll), Current#troll.id =/= Troll_id ->\r
- {struct, [\r
- {reply, "new_troll"},\r
- {troll_id, Current#troll.id},\r
- {message_id, Current#troll.id_minichat},\r
- {content, Current#troll.content}\r
- ]};\r
- _ ->\r
- % est-ce qu'il y a des nouveaux messages ?\r
- case euphorik_minichat_conversation:conversations(Racines_conversations, Message_count, Last_message_id, Main_page) of\r
- vide -> \r
- wait_event_bd_page_chat(),\r
- wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id, Main_page, Troll_id);\r
- Conversations ->\r
- % accrochez-vous ca va siouxer ;)\r
- {struct, [\r
- {reply, "new_messages"},\r
- {conversations, {array,\r
- lists:map(\r
- fun({Racine, {Conv, Plus}}) ->\r
- {struct, [\r
- {last_page, not Plus},\r
- {first, % le premier message de la conversation\r
- if Racine =:= undefined orelse Conv =:= [] ->\r
- null;\r
- true ->\r
- {Racine_id, _, _} = Racine,\r
- case euphorik_bd:message_by_id(Racine_id) of\r
- {ok, Mess} ->\r
- json_message(Mess, euphorik_bd:parents_id(Racine_id), User);\r
- _ ->\r
- null\r
- end\r
- end\r
- },\r
- {messages, {array,\r
- lists:map(\r
- fun({Mess, Repond_a}) ->\r
- json_message(Mess, Repond_a, User)\r
- end,\r
- Conv\r
- )\r
- }}\r
- ]}\r
- end,\r
- % on ajoute un 'undefined' correspondant à la premier conversation qui ne possède pas de racine\r
- % TODO : peut être à revoir car un peu lourd est compliqué\r
- aggregation_racines_conversations([undefined | Racines_conversations], Conversations)\r
- )\r
- }}\r
- ]}\r
- end\r
+% Attend un événement pour la page "Chat" et renvoie les messages manquants au client.\r
+wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id, Main_page) ->\r
+ % est-ce qu'il y a des nouveaux messages ?\r
+ case euphorik_minichat_conversation:conversations(Racines_conversations, Message_count, Last_message_id, Main_page) of\r
+ vide ->\r
+ wait_event_bd_page_chat(),\r
+ wait_event_page_chat(User, Racines_conversations, Message_count, Last_message_id, Main_page);\r
+ Conversations ->\r
+ % Accrochez-vous ca va siouxer ;).\r
+ {struct, [\r
+ {reply, "new_messages"},\r
+ {conversations, {array,\r
+ lists:map(\r
+ fun({Racine, {Conv, Plus}}) ->\r
+ {struct, [\r
+ {last_page, not Plus},\r
+ {first, % le premier message de la conversation\r
+ if Racine =:= undefined orelse Conv =:= [] ->\r
+ null;\r
+ true ->\r
+ {Racine_id, _, _} = Racine,\r
+ case euphorik_bd:message_by_id(Racine_id) of\r
+ {ok, Mess} ->\r
+ json_message(Mess, euphorik_bd:parents_id(Racine_id), User);\r
+ _ ->\r
+ null\r
+ end\r
+ end\r
+ },\r
+ {messages, {array,\r
+ lists:map(\r
+ fun({Mess, Repond_a}) ->\r
+ json_message(Mess, Repond_a, User)\r
+ end,\r
+ Conv\r
+ )\r
+ }}\r
+ ]}\r
+ end,\r
+ % on ajoute un 'undefined' correspondant à la premier conversation qui ne possède pas de racine\r
+ % TODO : peut être à revoir car un peu lourd est compliqué\r
+ aggregation_racines_conversations([undefined | Racines_conversations], Conversations)\r
+ )\r
+ }}\r
+ ]}\r
end.\r
- \r
\r
-aggregation_racines_conversations(L1, L2) -> \r
+\r
+aggregation_racines_conversations(L1, L2) ->\r
aggregation_racines_conversations(L1, L2, []).\r
aggregation_racines_conversations([], [], L) -> lists:reverse(L);\r
aggregation_racines_conversations([E1|R1], [E2|R2], L) ->\r
aggregation_racines_conversations(R1, R2, [{E1, E2} | L]).\r
- \r
+\r
\r
\r
% Attend un événement lié à la page 'chat'.\r
receive % attente d'un post\r
{mnesia_table_event, {write, minichat, _Message, [], _}} ->\r
ok;\r
- {mnesia_table_event, {write, troll, Troll, [Old_troll | _], _}} when Troll#troll.date_post =/= undefined, Old_troll#troll.date_post == undefined ->\r
- ok;\r
{tcp_closed, _} ->\r
exit(normal);\r
_ ->\r
wait_event_bd_page_chat()\r
% 60 minutes de timeout (on ne sais jamais)\r
% Après 60 minutes de connexion, le client doit donc reétablir une connexion\r
- after 1000 * 60 * 60 -> \r
+ after 1000 * 60 * 60 ->\r
timeout\r
end.\r
\r
\r
% Attent un événement concernant la page admin\r
-% Renvoie les trolls manquants posté après Last_id ou banned_ips_refresh.\r
-% Si pas de trolls alors attend un événement tel qu'un ajout, une modification ou une suppression.\r
-% renvoie :\r
-% {mod, Troll}\r
-% ou {add, [Trolls]}\r
-% ou {del, Troll_id}\r
-% ou banned_ips_refresh\r
+% banned_ips_refresh\r
% ou timeout\r
-wait_event_page_admin(Last_id) ->\r
- case {mnesia:subscribe({table, troll, detailed}), mnesia:subscribe({table, ip_table, detailed})} of\r
- {{error, E}, _ } -> E;\r
- {_, {error, E}} -> E;\r
- _ ->\r
- R = case euphorik_bd:trolls(Last_id) of\r
- [] -> % pas de trolls\r
- wait_event_page_admin();\r
- Trolls ->\r
- {add, Trolls}\r
- end,\r
- mnesia:unsubscribe({table, troll, detailed}),\r
- mnesia:unsubscribe({table, ip_table, detailed}),\r
- R\r
- end.\r
- \r
wait_event_page_admin() ->\r
- % s'il n'y a pas de trolls que l'utilisateur n'a pas connaissance alors on attend un événement\r
- receive\r
- % cas où un troll est choisit comme courant\r
- {mnesia_table_event, {write, troll, Troll, [Old_troll | _], _}}\r
- when Old_troll#troll.date_post =:= undefined, Troll#troll.date_post =/= undefined ->\r
- {del, Troll#troll.id};\r
- {mnesia_table_event, {write, troll, Troll, [_Old_troll | _], _}} ->\r
- {mod, Troll};\r
- {mnesia_table_event, {write, troll, Troll, [], _}} ->\r
- {add, [Troll]};\r
- {mnesia_table_event, {delete, troll, {troll, Id}, _, _}} ->\r
- {del, Id};\r
- {mnesia_table_event, {write, ip_table, IP, [Old_IP | _], _}}\r
- when Old_IP#ip_table.ban =/= IP#ip_table.ban; Old_IP#ip_table.ban_duration =/= IP#ip_table.ban_duration ->\r
- banned_ips_refresh;\r
- {tcp_closed, _} ->\r
- exit(normal);\r
+ case mnesia:subscribe({table, ip_table, detailed}) of\r
+ {error, E} -> E;\r
_ ->\r
- wait_event_page_admin()\r
- % 60 minutes de timeout (on ne sais jamais)\r
- % Après 60 minutes de connexion, le client doit donc reétablir une connexion\r
- after 1000 * 60 * 60 -> \r
- timeout\r
+ R = receive\r
+ {mnesia_table_event, {write, ip_table, IP, [Old_IP | _], _}}\r
+ when Old_IP#ip_table.ban =/= IP#ip_table.ban; Old_IP#ip_table.ban_duration =/= IP#ip_table.ban_duration ->\r
+ banned_ips_refresh;\r
+ {tcp_closed, _} ->\r
+ exit(normal);\r
+ _ ->\r
+ wait_event_page_admin()\r
+ % 60 minutes de timeout (on ne sais jamais)\r
+ % Après 60 minutes de connexion, le client doit donc reétablir une connexion\r
+ after 1000 * 60 * 60 ->\r
+ timeout\r
+ end,\r
+ mnesia:unsubscribe({table, ip_table, detailed}),\r
+ R\r
end.\r
- \r
- \r
+\r
+\r
% Un utilisateur envoie un message\r
% Answer_to est une liste d'id (int)\r
put_message(\r
_ ->\r
erreur(150)\r
end.\r
- \r
+\r
\r
% slapage d'un user (avertissement)\r
slap(\r
{ok, User1 = #user{ek_master = true, profile = Profile1}} ->\r
case euphorik_bd:user_by_id(User_id) of\r
{ok, User1} ->\r
- euphorik_bd:nouveau_message_sys(lists:flatten(io_lib:format("~s s'auto slap~s.", \r
+ euphorik_bd:nouveau_message_sys(lists:flatten(io_lib:format("~s s'auto slap~s.",\r
[\r
Profile1#profile.pseudo,\r
if Reason =/= [] -> " - Raison: " ++ Reason; true -> "" end\r
_ ->\r
erreur(170)\r
end.\r
- \r
- \r
-put_troll(\r
- [\r
- {cookie, Cookie},\r
- {content, Content}\r
- ]\r
-) ->\r
- % controle que l'utilisateur est un admin\r
- case euphorik_bd:user_by_cookie(Cookie) of\r
- {ok, User = #user{ek_master = true}} ->\r
- case euphorik_bd:put_troll(User#user.id, Content) of\r
- max_troll_reached_per_user ->\r
- erreur(180, [?NB_MAX_TROLL_WAITING_BY_USER]);\r
- max_troll_reached ->\r
- erreur(190, [?NB_MAX_TROLL_WAITING]);\r
- _Id ->\r
- json_reponse_ok()\r
- end;\r
- _ ->\r
- erreur(200)\r
- end.\r
- \r
- \r
-mod_troll(\r
- [\r
- {cookie, Cookie},\r
- {troll_id, Troll_id},\r
- {content, Content}\r
- ]\r
-) ->\r
- % controle que l'utilisateur est un admin\r
- case euphorik_bd:user_by_cookie(Cookie) of\r
- {ok, User = #user{ek_master = true}} ->\r
- User_id = User#user.id,\r
- case euphorik_bd:troll_by_id(Troll_id) of\r
- {ok, #troll{id_user = User_id}} ->\r
- euphorik_bd:mod_troll(Troll_id, Content),\r
- json_reponse_ok();\r
- _ ->\r
- erreur(210)\r
- end;\r
- _ ->\r
- erreur(220)\r
- end.\r
\r
- \r
-del_troll(\r
- [\r
- {cookie, Cookie},\r
- {troll_id, Troll_id}\r
- ]\r
-) -> \r
- % controle que l'utilisateur est un admin\r
- case euphorik_bd:user_by_cookie(Cookie) of\r
- {ok, User = #user{ek_master = true}} ->\r
- User_id = User#user.id,\r
- case euphorik_bd:troll_by_id(Troll_id) of\r
- {ok, #troll{id_user = User_id}} ->\r
- euphorik_bd:del_troll(Troll_id),\r
- json_reponse_ok();\r
- _ ->\r
- erreur(210)\r
- end;\r
- _ ->\r
- erreur(220)\r
- end.\r
- \r
- \r
+\r
unban_ip(\r
[\r
{cookie, Cookie},\r
_ ->\r
erreur(230)\r
end.\r
- \r
- \r
+\r
+\r
list_banned_ips(\r
[\r
{cookie, Cookie}\r
% Construit une erreur\r
erreur(Num, Args) ->\r
erreur_json(Num, lists:flatten(io_lib:format(euphorik_bd:get_texte(Num), Args))).\r
- \r
- \r
+\r
+\r
erreur(Num) ->\r
erreur_json(Num, euphorik_bd:get_texte(Num)).\r
- \r
- \r
+\r
+\r
erreur_json(Num, Mess) ->\r
{\r
struct, [\r
{error_message, Mess}\r
]\r
}.\r
- \r
- \r
+\r
+\r
% Formatage de minutes.\r
% par exemple : "1min", "45min", "1h23min", "1jour 2h34min"\r
format_minutes(Min) ->\r
true ->\r
" " ++ integer_to_list(Minutes) ++ " minute" ++ if Minutes > 1 -> "s"; true -> "" end\r
end.\r
- \r
- \r
+\r
+\r
% Formatage d'une heure\r
% local_time() -> string\r
format_date(Date) ->\r
Hier ->\r
"Hier ";\r
Annee =:= AnneeNow ->\r
- io_lib:format("~2.10.0B/~2.10.0B ", [Jour, Mois]); \r
+ io_lib:format("~2.10.0B/~2.10.0B ", [Jour, Mois]);\r
true ->\r
io_lib:format("~2.10.0B/~2.10.0B/~B ", [Jour, Mois, Annee])\r
end ++\r
\r
json_reponse_ok() ->\r
{struct, [{reply, "ok"}]}.\r
- \r
- \r
+\r
+\r
json_reponse_login_ok(#user{profile = Profile} = User) ->\r
{\r
struct, [\r
}}\r
]\r
}.\r
- \r
+\r
% Renvoie le message formaté en JSON.\r
% Mess est de type #minichat\r
% Repond_a est une liste d'id des messages auquel répond Mess\r
{content, Mess#minichat.contenu},\r
{root, Mess#minichat.racine_id},\r
{answer_to, {array, lists:map(\r
- fun(Id_mess) -> \r
+ fun(Id_mess) ->\r
{ok, M} = euphorik_bd:message_by_id(Id_mess),\r
{ok, User_reponse} = euphorik_bd:user_by_mess(M#minichat.id),\r
{struct, [{id, M#minichat.id}, {nick, M#minichat.pseudo}, {login, User_reponse#user.login}]}\r
%\r
% You should have received a copy of the GNU General Public License\r
% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
-% \r
+%\r
% Ce module est fait pour répondre à des requêtes JSON via 'AJAX'.\r
% Il est définit comme 'appmods' pour l'url "request" dans Yaws.\r
% Par exemple http://www.euphorik.ch/request abouti sur la fonction out/1 de ce module.\r
\r
-module(euphorik_requests).\r
-export([out/1]).\r
--include_lib("yaws/include/yaws_api.hrl").\r
+-include_lib("yaws_api.hrl").\r
-include("../include/euphorik_defines.hrl").\r
\r
\r
% Point d'entrée pour les requêtes AJAX sur http://www.euphorik.ch/request.\r
-out(A) -> \r
+out(A) ->\r
IP = case inet:peername(A#arg.clisock) of\r
{ok, {Adresse, _Port}} -> Adresse;\r
_ -> inconnue\r
)))\r
end\r
).\r
- \r
+\r
\r
% Authentification d'un client.\r
traiter_action("authentification", JSON, IP) ->\r
% Un ekMaster slap un utilisateur.\r
traiter_action("slap", JSON, _) ->\r
euphorik_protocole:slap(JSON);\r
-% Un ekMaster envoie un nouveau troll.\r
-traiter_action("put_troll", JSON, _) ->\r
- euphorik_protocole:put_troll(JSON);\r
-% Un ekMaster modifie un troll.\r
-traiter_action("mod_troll", JSON, _) ->\r
- euphorik_protocole:mod_troll(JSON);\r
-% Un ekMaster supprime un troll.\r
-traiter_action("del_troll", JSON, _) ->\r
- euphorik_protocole:del_troll(JSON);\r
% Un ekMaster demande la liste des ips bannies.\r
traiter_action("list_banned_ips", JSON, _) ->\r
euphorik_protocole:list_banned_ips(JSON);\r
% Un ekMaster débannie une ip.\r
traiter_action("unban", JSON, _) ->\r
euphorik_protocole:unban_ip(JSON).\r
-
\ No newline at end of file
-% 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 <http://www.gnu.org/licenses/>.
-%
-% Module de test de euphorik.
-% Crée un certain nombre d'utilisateur et post des messages aléatoire.
-
-
--module(euphorik_test).
--export([
- bench_write_minichat/1,
- start/2,
- stop/1,
- bench_get_messages/0,
- bench_get_messages_avec_2_conversations/0
-]).
--include("../include/euphorik_bd.hrl").
+% coding: utf-8\r
+% Copyright 2008 Grégory Burri\r
+%\r
+% This file is part of Euphorik.\r
+%\r
+% Euphorik is free software: you can redistribute it and/or modify\r
+% it under the terms of the GNU General Public License as published by\r
+% the Free Software Foundation, either version 3 of the License, or\r
+% (at your option) any later version.\r
+%\r
+% Euphorik is distributed in the hope that it will be useful,\r
+% but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+% GNU General Public License for more details.\r
+%\r
+% You should have received a copy of the GNU General Public License\r
+% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
+%\r
+% Module de test de euphorik.\r
+% Crée un certain nombre d'utilisateur et post des messages aléatoire.\r
+\r
+\r
+-module(euphorik_test).\r
+-export([\r
+ bench_write_minichat/1,\r
+ start/2,\r
+ stop/1,\r
+ bench_get_messages/0,\r
+ bench_get_messages_avec_2_conversations/0\r
+]).\r
+-include("../include/euphorik_bd.hrl").\r
\r
% les intervalles en seconde min en max entre deux postes de message d'un utilisateur\r
% le temps d'attente est choisi au hasard entre ces deux valeurs\r
-define(INTERVALLE_MIN, 2).\r
--define(INTERVALLE_MAX, 5).
-
-
-% N est le nombre d'utilisateur
-% M est le nombre de message que chaque utilisateur va poster
-start(N, M) ->
- Ids = creer_users(N),
- lists:map(
- fun(Id) ->
- timer:sleep(100),
- spawn(
- fun() ->
- {A1, A2, A3} = now(),
- random:seed(A1, A2, A3),
- loop(Id, M)
- end
- )
- end,
- Ids
- ).
-
-stop(Pids) ->
- lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids).
-
-% des trucs qui trainent
-bench_get_messages() ->
- T = [
- {page,"chat"},
- {cookie,"5G84A5CJXMCPEHNI8T5A9"},
- {message_count,40},
- {last_message_id,0},
- {main_page,1},
- {troll_id,0},
- {conversations,{array,[]}}
- ],
- moyenne_temps(euphorik_protocole, wait_event, [T], 20).
-bench_get_messages_avec_2_conversations() ->
- T = [
- {page,"chat"},
- {cookie,"5G84A5CJXMCPEHNI8T5A9"},
- {message_count,40},
- {last_message_id,0},
- {main_page,1},
- {troll_id,0},
- {conversations,{array, [
- {struct, [
- {root, 921},
- {page,1},
- {last_message_id,0}
- ]},
- {struct, [
- {root, 772},
- {page, 1},
- {last_message_id, 0}
- ]}
- ]}}
- ],
- 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) ->
- Temps_acc / Total;
-moyenne_temps(Module, Fun, Args, N, Total, Temps_acc) ->
- {Temps, _} = timer:tc(Module, Fun, Args),
- moyenne_temps(Module, Fun, Args, N - 1, Total, Temps_acc + Temps).
-
-
-% Crée N user avec des noms aléatoires et renvoie la liste des id.
-creer_users(N) ->
- creer_users(N, []).
-creer_users(0, Ids) -> lists:map(fun(#user{id = Id}) -> Id end, Ids);
-creer_users(N, Ids) ->
- creer_users(N - 1, [euphorik_bd:nouveau_user(mot_rand(random:uniform(4) + 4), "", "", #profile{}) | Ids ]).
-
-
-% crée un message aléatoire et le renvoie
-message_rand() ->
- lists:flatten(message_rand(random:uniform(10), [])).
-message_rand(0, Mots) -> Mots;
-message_rand(N, Mots) ->
- message_rand(N - 1, [mot_rand(random:uniform(2) + 5), $ | Mots]).
-
-
-% Renvoie une succession de lettre aléatoire
-mot_rand(L) ->
- mot_rand(L, []).
-mot_rand(0, Mot) -> Mot;
-mot_rand(L, Mot) ->
- mot_rand(L - 1, [random:uniform($z - $a + 1) + $a - 1 | 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.95
-% 2 : 0.04
-% 3 : 0.01
-messages_id_rand() ->
- R = random:uniform(),
- if R =< 0.1 ->
- [];
- true ->
- Messages = lists:map(fun(#minichat{id = Id}) -> Id end, euphorik_bd:messages(8)),
- if
- R > 0.1 andalso R =< 0.95 ->
- tire_element_rand(1, Messages);
- R > 0.95 andalso R =< 0.99 ->
- tire_element_rand(2, Messages);
- true ->
- tire_element_rand(3, Messages)
- end
- end.
-
-
-% tire N element distinct parmis la liste L proposée
-tire_element_rand(N, L) when N =< length(L) ->
- tire_element_rand(N, L, []);
-tire_element_rand(_, _) ->
- [].
-tire_element_rand(0, _, Elements) -> Elements;
-tire_element_rand(N, L, Elements) ->
- E = lists:nth(random:uniform(length(L)), L),
- E_se_trouve_dans_Elements = lists:any(fun(E2) -> E2 =:= E end, Elements),
- if E_se_trouve_dans_Elements -> % si E a déjà été tiré on recommence sans rien changer
- tire_element_rand(N, L, Elements);
- true ->
- tire_element_rand(N-1, L, [E | Elements])
- end.
-
-loop(User_id, 0) ->
- io:format("~p a fini~n", [User_id]);
-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()},
- % 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]),
- 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
+-define(INTERVALLE_MAX, 5).\r
+\r
+\r
+% N est le nombre d'utilisateur\r
+% M est le nombre de message que chaque utilisateur va poster\r
+start(N, M) ->\r
+ Ids = creer_users(N),\r
+ lists:map(\r
+ fun(Id) ->\r
+ timer:sleep(100),\r
+ spawn(\r
+ fun() ->\r
+ {A1, A2, A3} = now(),\r
+ random:seed(A1, A2, A3),\r
+ loop(Id, M)\r
+ end\r
+ )\r
+ end,\r
+ Ids\r
+ ).\r
+\r
+stop(Pids) ->\r
+ lists:foreach(fun(Pid) -> exit(Pid, kill) end, Pids).\r
+\r
+% des trucs qui trainent\r
+bench_get_messages() ->\r
+ T = [\r
+ {page,"chat"},\r
+ {cookie,"5G84A5CJXMCPEHNI8T5A9"},\r
+ {message_count,40},\r
+ {last_message_id,0},\r
+ {main_page,1},\r
+ {conversations,{array,[]}}\r
+ ],\r
+ moyenne_temps(euphorik_protocole, wait_event, [T], 20).\r
+bench_get_messages_avec_2_conversations() ->\r
+ T = [\r
+ {page,"chat"},\r
+ {cookie,"5G84A5CJXMCPEHNI8T5A9"},\r
+ {message_count,40},\r
+ {last_message_id,0},\r
+ {main_page,1},\r
+ {conversations,{array, [\r
+ {struct, [\r
+ {root, 921},\r
+ {page,1},\r
+ {last_message_id,0}\r
+ ]},\r
+ {struct, [\r
+ {root, 772},\r
+ {page, 1},\r
+ {last_message_id, 0}\r
+ ]}\r
+ ]}}\r
+ ],\r
+ moyenne_temps(euphorik_protocole, wait_event, [T], 20).\r
+moyenne_temps(Module, Fun, Args, N) ->\r
+ moyenne_temps(Module, Fun, Args, N, N, 0).\r
+moyenne_temps(_, _, _, 0, Total, Temps_acc) ->\r
+ Temps_acc / Total;\r
+moyenne_temps(Module, Fun, Args, N, Total, Temps_acc) ->\r
+ {Temps, _} = timer:tc(Module, Fun, Args),\r
+ moyenne_temps(Module, Fun, Args, N - 1, Total, Temps_acc + Temps).\r
+\r
+\r
+% Crée N user avec des noms aléatoires et renvoie la liste des id.\r
+creer_users(N) ->\r
+ creer_users(N, []).\r
+creer_users(0, Ids) -> lists:map(fun(#user{id = Id}) -> Id end, Ids);\r
+creer_users(N, Ids) ->\r
+ creer_users(N - 1, [euphorik_bd:nouveau_user(mot_rand(random:uniform(4) + 4), "", "", #profile{}) | Ids ]).\r
+\r
+\r
+% crée un message aléatoire et le renvoie\r
+message_rand() ->\r
+ lists:flatten(message_rand(random:uniform(10), [])).\r
+message_rand(0, Mots) -> Mots;\r
+message_rand(N, Mots) ->\r
+ message_rand(N - 1, [mot_rand(random:uniform(2) + 5), $ | Mots]).\r
+\r
+\r
+% Renvoie une succession de lettre aléatoire\r
+mot_rand(L) ->\r
+ mot_rand(L, []).\r
+mot_rand(0, Mot) -> Mot;\r
+mot_rand(L, Mot) ->\r
+ mot_rand(L - 1, [random:uniform($z - $a + 1) + $a - 1 | Mot]).\r
+\r
+\r
+% Tire au hasard de 0 à 3 messages sur les 10 derniers postés, renvoie une liste de int()\r
+% répartition :\r
+% 0 : 0.1\r
+% 1 : 0.95\r
+% 2 : 0.04\r
+% 3 : 0.01\r
+messages_id_rand() ->\r
+ R = random:uniform(),\r
+ if R =< 0.1 ->\r
+ [];\r
+ true ->\r
+ Messages = lists:map(fun(#minichat{id = Id}) -> Id end, euphorik_bd:messages(8)),\r
+ if\r
+ R > 0.1 andalso R =< 0.95 ->\r
+ tire_element_rand(1, Messages);\r
+ R > 0.95 andalso R =< 0.99 ->\r
+ tire_element_rand(2, Messages);\r
+ true ->\r
+ tire_element_rand(3, Messages)\r
+ end\r
+ end.\r
+\r
+\r
+% tire N element distinct parmis la liste L proposée\r
+tire_element_rand(N, L) when N =< length(L) ->\r
+ tire_element_rand(N, L, []);\r
+tire_element_rand(_, _) ->\r
+ [].\r
+tire_element_rand(0, _, Elements) -> Elements;\r
+tire_element_rand(N, L, Elements) ->\r
+ E = lists:nth(random:uniform(length(L)), L),\r
+ E_se_trouve_dans_Elements = lists:any(fun(E2) -> E2 =:= E end, Elements),\r
+ if E_se_trouve_dans_Elements -> % si E a déjà été tiré on recommence sans rien changer\r
+ tire_element_rand(N, L, Elements);\r
+ true ->\r
+ tire_element_rand(N-1, L, [E | Elements])\r
+ end.\r
+\r
+loop(User_id, 0) ->\r
+ io:format("~p a fini~n", [User_id]);\r
+loop(User_id, M) ->\r
+ % attend un temp aléatoire compris entre INTERVALLE_MIN sec et INTERVALLE_MAX sec\r
+ timer:sleep(1000 * (random:uniform(?INTERVALLE_MAX - ?INTERVALLE_MIN + 1) + ?INTERVALLE_MIN - 1)),\r
+ % poste un message aléatoire par une personne aléatoire répondant à des messages aléatoires\r
+ {Message, Repond_a} = {message_rand(), messages_id_rand()},\r
+ % io:format("~p poste ~p et repond a ~w~n", [User_id, Message, Repond_a]),\r
+ case euphorik_bd:nouveau_message(Message, User_id, Repond_a) of\r
+ {erreur, E} ->\r
+ io:format("~p : erreur : ~p~n", [User_id, E]),\r
+ loop(User_id, M);\r
+ _ ->\r
+ loop(User_id, M - 1)\r
+ end.\r
+\r
+\r
+% Permet de tester la vitesse d'écriture en fonction de la\r
+% taille de la BD\r
+% voir : http://erlang.org/pipermail/erlang-questions/2008-October/038697.html\r
+bench_write_minichat(Filename) ->\r
+ Times = bench_write_minichat(1, []),\r
+ {ok, File} = file:open(Filename, [write]),\r
+ lists:foreach(\r
+ fun({Id, Time}) ->\r
+ io:format(File, "~w ~w~n", [Id, Time])\r
+ end,\r
+ Times\r
+ ),\r
+ file:close(File).\r
+bench_write_minichat(100000, Temps) -> Temps;\r
+bench_write_minichat(N, Temps) ->\r
+ {T, _} = timer:tc(mnesia, transaction, [fun() ->\r
+ Id = mnesia:dirty_update_counter(counter, minichat, 1),\r
+ mnesia:write(#minichat{\r
+ id = Id,\r
+ auteur_id = random:uniform(10000),\r
+ date = now(),\r
+ pseudo = "Test",\r
+ contenu = "Blabla blabla bla.",\r
+ racine_id = random:uniform(10000)\r
+ })\r
+ end]),\r
+ bench_write_minichat(N + 1, if N rem 500 =:= 0 -> [{N, T} | Temps]; true -> Temps end).\r
+\r
+\r
+\r
-% 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 <http://www.gnu.org/licenses/>.
-%
-% @author GBurri
-
-
-% Version de la BD
--define(VERSION_BD, 3).
--define(TABLES, [counter, proprietes, minichat, reponse_minichat, user, ip_table, troll]).
-
-
-% Pour générer des id
--record(counter,
- {
- key,
- value
- }).
-
-
-% Mémorse toutes les propriétés, entre autre la version des données
--record(proprietes,
- {
- nom,
- valeur
- }).
-
-
-% Contient tous les textes que peut envoyer le serveur vers client.
--record(texte,
- {
- id,
- fr
- }).
-
-
-% décrit un enregistrement d'un message
--record(minichat,
- {
- id, % integer
- auteur_id, % -> #user.id
- 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
- status = normal % can be equal to normal, censored or deleted
- }).
-
-
-% type bag
-% 'repondant' repond à 'cible'
--record(reponse_minichat,
- {
- repondant, % -> #minichat.id
- cible % -> #minichat.id
- }).
-
-
--record(profile, % attention : pas une table !
- {
- pseudo = [], % string()
- email = [], % string()
- css = [], % string()
- nick_format = nick, %atom(), peut valoir 'nick', 'login' ou 'nick_login'
- view_times = true,
- view_tooltips = true,
- 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?}
+% coding: utf-8\r
+% Copyright 2008 Grégory Burri\r
+%\r
+% This file is part of Euphorik.\r
+%\r
+% Euphorik is free software: you can redistribute it and/or modify\r
+% it under the terms of the GNU General Public License as published by\r
+% the Free Software Foundation, either version 3 of the License, or\r
+% (at your option) any later version.\r
+%\r
+% Euphorik is distributed in the hope that it will be useful,\r
+% but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+% GNU General Public License for more details.\r
+%\r
+% You should have received a copy of the GNU General Public License\r
+% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
+%\r
+% @author GBurri\r
+\r
+\r
+% Version de la BD\r
+-define(VERSION_BD, 3).\r
+-define(TABLES, [counter, proprietes, minichat, reponse_minichat, user, ip_table, troll]).\r
+\r
+\r
+% Pour générer des id\r
+-record(counter,\r
+ {\r
+ key,\r
+ value\r
}).\r
- \r
-
--record(user,
- {
- id,
- cookie, % string()
- login = [], % string()
- password = [], % string() (md5)
- profile = #profile{},
- date_creation, % erlang:now()
- date_derniere_connexion, % erlang:now(), est mis à jour lors de n'importe quelle activitée (envoie de message par exemple)
- indice_flood = 0, % integer() est incrémenté lorsque l'utilisateur envoie trop rapidement des messages.
- ek_master = false,
- last_ip = undefined % integer(), undefined si inconnu
- }).
-
-
-% identificateur : (ip)
--record(ip_table,
- {
- ip, % {integer(), integer(), integer(), integer()}
- ban = undefined, % la date du dernier bannissement
- ban_duration = 0, % le temps de ban en minute
- nb_try_register = 0,
- nb_try_login = 0, % pour l'instant pas utilisé
- date_last_try_register,
- date_last_try_login % pour l'instant pas utilisé
- }).
-
-
--record(troll,
- {
- id,
+\r
+\r
+% Mémorse toutes les propriétés, entre autre la version des données\r
+-record(proprietes,\r
+ {\r
+ nom,\r
+ valeur\r
+ }).\r
+\r
+\r
+% Contient tous les textes que peut envoyer le serveur vers client.\r
+-record(texte,\r
+ {\r
+ id,\r
+ fr\r
+ }).\r
+\r
+\r
+% décrit un enregistrement d'un message\r
+-record(minichat,\r
+ {\r
+ id, % integer\r
+ auteur_id, % -> #user.id\r
+ date, % erlang:now()\r
+ pseudo, % chaine de caractère\r
+ contenu, % chaine de caractère\r
+ racine_id = undefined, % la racine, par défaut correspond à l'id du message\r
+ status = normal % can be equal to normal, censored or deleted\r
+ }).\r
+\r
+\r
+% type bag\r
+% 'repondant' repond à 'cible'\r
+-record(reponse_minichat,\r
+ {\r
+ repondant, % -> #minichat.id\r
+ cible % -> #minichat.id\r
+ }).\r
+\r
+\r
+-record(profile, % attention : pas une table !\r
+ {\r
+ pseudo = [], % string()\r
+ email = [], % string()\r
+ css = [], % string()\r
+ nick_format = nick, %atom(), peut valoir 'nick', 'login' ou 'nick_login'\r
+ view_times = true,\r
+ view_tooltips = true,\r
+ ostentatious_master = light, % peut valoir invisible, light ou heavy. seulement pour ek_master\r
+ chat_order = reverse, % peut valoir chrono ou reverse\r
+ conversations = [] % [{integer(), bool}], la liste des messages correspondant au conversation {racine, reduite?}\r
+ }).\r
+\r
+\r
+-record(user,\r
+ {\r
+ id,\r
+ cookie, % string()\r
+ login = [], % string()\r
+ password = [], % string() (md5)\r
+ profile = #profile{},\r
+ date_creation, % erlang:now()\r
+ date_derniere_connexion, % erlang:now(), est mis à jour lors de n'importe quelle activitée (envoie de message par exemple)\r
+ indice_flood = 0, % integer() est incrémenté lorsque l'utilisateur envoie trop rapidement des messages.\r
+ ek_master = false,\r
+ last_ip = undefined % integer(), undefined si inconnu\r
+ }).\r
+\r
+\r
+% identificateur : (ip)\r
+-record(ip_table,\r
+ {\r
+ ip, % {integer(), integer(), integer(), integer()}\r
+ ban = undefined, % la date du dernier bannissement\r
+ ban_duration = 0, % le temps de ban en minute\r
+ nb_try_register = 0,\r
+ nb_try_login = 0, % pour l'instant pas utilisé\r
+ date_last_try_register,\r
+ date_last_try_login % pour l'instant pas utilisé\r
+ }).\r
+\r
+\r
+-record(troll,\r
+ {\r
+ id,\r
id_user,\r
- 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
- }).
-
\ No newline at end of file
+ id_minichat = undefined, % l'id du message associé\r
+ date_create, % erlang:now()\r
+ date_post = undefined, % date à laquelle le troll est affiché sur la page principale. undefined initialement puis erlang:now() quand affiché\r
+ content % chaine de caractère\r
+ }).\r
-define(DUREE_SPAM, 1000). % ms
% Lorsque l'indice de spam d'un utilisateur atteind cette valeur alors il ne peut plus poster pendant un moment
-define(INDICE_SPAM_MAX, 6).
-% Un utilisateur ayant trop spamé est bloqué pendant ce temps
+% Un utilisateur ayant trop spamé est bloqué pendant ce temps
-define(DUREE_BLOCAGE_SPAM, 20000). % ms
% le temps entre deux tentatives de register pour compter un flood
-define(TEMPS_FLOOD_REGISTER, 1500). % 1500 ms
% après 5 flood l'ip fautive est considérée comme bannie
--define(NB_MAX_FLOOD_REGISTER, 5).
+-define(NB_MAX_FLOOD_REGISTER, 5).
% le nombre max de troll qui peuvent être en attente d'être posté (tous les utilisateurs réunis)
main(_) ->
net_kernel:start([tv, shortnames]),
- Yaws = yaws_dev@flynux,
+ Yaws = yaws_dev@X220,
io:format("Connexion à Yaws : ~p~n", [net_adm:ping(Yaws)]),
mnesia:start(),
mnesia:change_config(extra_db_nodes, nodes()),
-#!/usr/bin/env escript
-% coding: utf-8
+#!/usr/bin/env escript\r
+% coding: utf-8\r
% Copyright 2008 Grégory Burri\r
%\r
% This file is part of Euphorik.\r
% GNU General Public License for more details.\r
%\r
% You should have received a copy of the GNU General Public License\r
-% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.
+% along with Euphorik. If not, see <http://www.gnu.org/licenses/>.\r
\r
-% 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
+% This file replace the old one 'tools.rb' written in a crapy language ;)\r
+% TODO :\r
+% - création de unit tests (voir eunit) et validation avant la mise en prod\r
\r
\r
main(Args) ->\r
% A simple fonction to log message.\r
log(Str) ->\r
io:format("===== ~s =====~n", [Str]).\r
- \r
+\r
\r
% Execute an OS commande and print the result to stdout.\r
cmd(Commande_str) ->\r
- cmd(Commande_str, []). \r
+ cmd(Commande_str, []).\r
cmd(Commande_str, Params) ->\r
io:format("~s~n", [os:cmd(lists:flatten(io_lib:format(Commande_str, Params)))]).\r
\r
start_server(),\r
update_server().\r
\r
- \r
+\r
% Compile the Erlang modules.\r
compile_server_part(Uri) ->\r
todo.\r
- \r
+\r
\r
% Create the 'var' folder if it doesn't exist.\r
make_var_directory(Uri) ->\r
todo.\r
- \r
- \r
+\r
+\r
% Copy files from developpement env to production server.\r
copy_files(Uri) ->\r
copy_static_part(Uri),\r
copy_packed_js(Uri).\r
- \r
- \r
+\r
+\r
% Copy all static files like modules, styles, pages, etc.\r
copy_static_part(Uri) ->\r
%~ creer_rep('modules')\r
%~ system("rsync -r --exclude 'euphorik_test.beam' modules/ebin #{@uri}:#{@rep}/modules")\r
%~ system("rsync -r modules/include #{@uri}:#{@rep}/modules")\r
todo.\r
- \r
+\r
\r
% Minify and pack JavaScript in one file then copy it to ther server.\r
copy_packed_js(Uri) ->\r
todo.\r
- \r
- \r
+\r
+\r
% Define the rights for the copied folder et files.\r
define_files_rights(Uri) ->\r
- todo. \r
- \r
- \r
+ todo.\r
+\r
+\r
% Start the server if it not already started (in preproduction case only).\r
start_server() ->\r
todo.\r
- \r
- \r
-% Run a erlang script to \r
+\r
+\r
+% Run a erlang script to\r
update_server() ->\r
todo.\r
-
+\r