From: Greg Burri Date: Wed, 7 May 2008 19:06:50 +0000 (+0000) Subject: ADD ajout du bannissement (pas fini) X-Git-Tag: 1.0.0^2~102 X-Git-Url: https://git.euphorik.ch/?a=commitdiff_plain;h=13bf850da2316cde3ad2ff8d5c26fb32928bf7b4;p=euphorik.git ADD ajout du bannissement (pas fini) ADD du statut de ekMaster (admin) ADD limitation du nombre de register qu'il est possible de faire à la suite (anti flood) --- diff --git a/css/1/pageMinichat.css b/css/1/pageMinichat.css index fac422e..d7cd580 100755 --- a/css/1/pageMinichat.css +++ b/css/1/pageMinichat.css @@ -134,6 +134,10 @@ color: #76ff33; } +#page.minichat div.message.ekMaster .pseudo { + color: #ffffff; +} + #page.minichat div.message .pseudo .login { margin-left: 2px; font-size: 8px; diff --git a/doc/TODO.txt b/doc/TODO.txt index e9452f0..a36c000 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -16,7 +16,6 @@ * Traiter les tags TODO et FIXME dans le code * Mettre les constantes au niveau du serveur dans euphorik_defines.hrl (par exemple les temps lié au flood) * Cleaner le code (erl, js, xhtml, css) et eventuellement profiler un peu (le refresh est lent sous opera) -* Restructurer le code Erlang : déplacer certaines fonctions d'un module à l'autre (ev. créer des modules) * Choisir une licence et la mettre un peu partout dans les sources, voir : http://www.gnu.org/licenses/gpl-howto.fr.html * Finir le script de mise en production * Make des modules. @@ -148,6 +147,7 @@ [ok] Tester avec des caractères exotiques (jap, coréen, etc..) [ok] Modifier la syntaxe des smiles actuels (pour pas qu'ils entre en conflit avec totoz) [ok] Trouver un moyen pour éviter la création à la suite de plusieurs comptes (via register). +[ok] Restructurer le code Erlang : déplacer certaines fonctions d'un module à l'autre (ev. créer des modules) === Bugs === diff --git a/doc/protocole3.txt b/doc/protocole3.txt index feae1f0..f0b0b38 100644 --- a/doc/protocole3.txt +++ b/doc/protocole3.txt @@ -173,6 +173,7 @@ Le format de la date n'est pas formel. "answer_to" : [ { "id" : 123, "nick" : "Pierre", "login" : "pierre_45" } ] + "ek_master" : true | false } ] } @@ -229,7 +230,7 @@ c -> s { "action" : "ban", "cookie" : "LKJDLAKSJBFLKASN", - "duration" : 3, // en heure + "duration" : 15, // en minute "user_id" : 67 } diff --git a/js/euphorik.js b/js/euphorik.js index 3503c7e..2d64fe2 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -305,7 +305,8 @@ Formateur.prototype.traiterLiensConv = function(M) } /** - * FIXME : Cette méthode est attrocement lourde ! A optimiser. + * FIXME : Cette méthode est attrocement lourde ! A optimiser. + * moyenne su échantillon : 234ms */ Formateur.prototype.traiterSmiles = function(M) { @@ -426,7 +427,7 @@ Client.prototype.resetDonneesPersonnelles = function() this.nickFormat = "nick" this.pagePrincipale = 1 - this.ek_master = false + this.ekMaster = false // les conversations, une conversation est un objet possédant les attributs suivants : // - racine (entier) @@ -707,7 +708,7 @@ Client.prototype.chargerDonnees = function(data) // les conversations thisClient.conversations = data["conversations"] - thisClient.ek_master = data["ek_master"] + thisClient.ekMaster = data["ek_master"] } this.dernierMessageErreur = data["error_message"] } diff --git a/js/pageMinichat.js b/js/pageMinichat.js index c118c54..2be7ca5 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -250,6 +250,7 @@ function Message(id, date, pseudo, login, contenu) this.appartientAuClient = false this.clientARepondu = false this.estUneReponse = false + this.ekMaster = false this.systeme = false // est-ce un message 'système' ? @@ -353,11 +354,11 @@ function Conversation(num, util, formateur, client) } /** - * Défini les fonctions (callback) appelées lorsque l'on change de page. + * Défini la page courante et s'il l'on se trouve sur la dernière page. * @pageCourante la page courante * @dernierePage true si c'est la dernière page sinon false */ -Conversation.prototype.eventsPage = function(pageCourante, dernierePage) +Conversation.prototype.setPage = function(pageCourante, dernierePage) { jQuery("#conversations #" + this.getId() + " .numPage").text(pageCourante) jQuery("#conversations #" + this.getId() + " .next").css("display", pageCourante == 1 ? "none" : "inline") @@ -430,6 +431,9 @@ Conversation.prototype.ajouterMessage = function(message) delete this.messagesParId[this.messages.shift().id] } +/** + * FIXME : méthode très lourde. ne serait-ce pas mieux de virer d'un coup l'élément conversation et d'en remettre un vide ? + */ Conversation.prototype.viderMessages = function() { this.messages = new Array() @@ -440,6 +444,7 @@ Conversation.prototype.viderMessages = function() /** * Après l'ajout d'un ou plusieurs message cette méthode est appelée afin * d'afficher les messages non-affichés. + * FIXME : méthode super lourde, à optimiser. * @param funClickExtract fonction (fun(numMess)) appellée lors du clic sur un bouton "extraire" */ Conversation.prototype.flush = function(funClickOuvrirConv) @@ -475,6 +480,7 @@ Conversation.prototype.flush = function(funClickOuvrirConv) (this.messages[i].clientARepondu ? " repondu" : "") + (this.messages[i].estUneReponse ? " reponse" : "") + (this.messages[i].systeme ? " systeme" : "") + + (this.messages[i].ekMaster ? " ekMaster" : "") + "\">" + "
>
" + "[" + message.date + "]" + @@ -498,7 +504,7 @@ Conversation.prototype.flush = function(funClickOuvrirConv) if (nbMessagesAffiche > this.nbMessageMax) jQuery("#conversations #" + this.getId() + " .message").slice(this.nbMessageMax, nbMessagesAffiche).empty() - // Ajoute les événements liés à chaque message + // ajoute les événements liés à chaque nouveau message jQuery("#conversations #" + this.getId() + " .message").filter(function(){return parseInt(jQuery(this).attr("id"), 36) > thisConversation.idDernierMessageAffiche}).each( function() { @@ -649,12 +655,24 @@ Messages.prototype.getJSONConversations = function() * Ajoute un ensemble de messages puis les affiches. * @param elements un tableau d'éléments JSON représentant les messages, voir protocole.txt * @param numConversation le numéro de la conversation auquel appartiennent les messages + * @return true si les messages on été ajoutés, false si la conversation n'existe pas et qu'il n'y a pas de message */ Messages.prototype.ajouterMessages = function(elements, numConversation) { + if (elements["messages"].length == 0 && typeof(this.conversations[numConversation]) == "undefined") + return false + for (var i = 0; i < elements["messages"].length; i++) this.ajouterMessage(elements["messages"][i], numConversation) this.flush(numConversation) + + // renseigne la conversation sur la page courante et si c'est la dernière + this.conversations[numConversation].setPage( + numConversation == 0 ? this.client.pagePrincipale : this.client.conversations[numConversation - 1].page, + elements["last_page"] + ) + + return true } /** @@ -670,10 +688,6 @@ Messages.prototype.ajouterMessage = function(element, numConversation) // pas d'utilisation de jquery pour des raisons de performance var id = element["id"] - // Obsolète - /*if (this.idDernierMessage == null || id > this.idDernierMessage) - this.idDernierMessage = id*/ - var message = new Message( id, element["date"], @@ -687,6 +701,7 @@ Messages.prototype.ajouterMessage = function(element, numConversation) message.estUneReponse = element["is_a_reply"] message.systeme = element["system"] message.setRepondA(element["answer_to"]) + message.ekMaster = element["ek_master"] if (this.conversations[numConversation] == null) { @@ -700,7 +715,7 @@ Messages.prototype.ajouterMessage = function(element, numConversation) { thisPage.util.replaceSelection( jQuery("form input.message")[0], - "{" + thisMessages.client.conversations[num-1].root + "}" + "{" + thisMessages.client.conversations[num-1].root.toString(36) + "}" ) } ) @@ -857,16 +872,14 @@ Messages.prototype.rafraichirMessages = function(vider) // ajoute les messages reçus à leur conversation respective for (var numConv = 0; numConv < data["conversations"].length; numConv++) { - // ya pas de nouveaux message -> on passe à la prochaine conversation - if (data["conversations"][numConv]["messages"].length == 0) continue - - thisMessages.ajouterMessages(data["conversations"][numConv], numConv) + // ya pas de nouveaux message -> on passe à la prochaine conversation FIXME : marche pas + //if (data["conversations"][numConv]["messages"].length == 0) continue - // définit les événements liés à la conversation - thisMessages.conversations[numConv].eventsPage( - numConv == 0 ? thisMessages.client.pagePrincipale : thisMessages.client.conversations[numConv - 1].page, - data["conversations"][numConv]["last_page"] - ) + if (! thisMessages.ajouterMessages(data["conversations"][numConv], numConv)) + { + thisMessages.util.messageDialogue("La conversation {" + thisMessages.client.conversations[numConv -1].root.toString(36) + "} n'existe pas") + thisMessages.client.supprimerConversation(numConv - 1) + } } // rappel de la fonction dans 100 ms diff --git a/modules/erl/euphorik_bd.erl b/modules/erl/euphorik_bd.erl index e114b52..678505b 100755 --- a/modules/erl/euphorik_bd.erl +++ b/modules/erl/euphorik_bd.erl @@ -17,6 +17,7 @@ nouveau_user/3, set_profile/9, update_date_derniere_connexion/1, + update_ip/2, update_pseudo_user/2, users/0, user_by_cookie/1, @@ -24,6 +25,7 @@ user_by_login/1, user_by_login_password/2, user_by_mess/1, + toggle_ek_master/1, % messages : nouveau_message/3, @@ -39,6 +41,13 @@ a_repondu_a_message/2, possede_message/2, + % ip : + ip_table/0, + ban/2, + + % versions : + update_version/1, + % utiles : can_register/1, resultat_transaction/1 @@ -172,10 +181,10 @@ set_profile(Cookie, Login, Password, Pseudo, Email, Css, Nick_format, Page_princ % Met à jour la date de la dernière connexion d'un utilisateur à maintenant -update_date_derniere_connexion(UserId) -> +update_date_derniere_connexion(User_id) -> mnesia:transaction( fun() -> - case mnesia:wread({user, UserId}) of + case mnesia:wread({user, User_id}) of [User] -> mnesia:write(User#user{date_derniere_connexion = now()}); _ -> @@ -183,7 +192,21 @@ update_date_derniere_connexion(UserId) -> end end ). - + + +% Met à jour l'ip d'un user +update_ip(User_id, IP) -> + mnesia:transaction( + fun() -> + case mnesia:wread({user, User_id}) of + [User] -> + mnesia:write(User#user{last_ip = IP}); + _ -> + mnesia:abort("update_ip: User inconnu") + end + end + ). + % Met à jour le pseudo du user update_pseudo_user(UserId, Pseudo) -> @@ -244,6 +267,19 @@ user_by_login(Login) -> )). +toggle_ek_master(User_id) -> + resultat_transaction(mnesia:transaction( + fun() -> + Users = qlc:e(qlc:q([E || E <- mnesia:table(user), E#user.id =:= User_id])), + case Users of + [User] -> + mnesia:write(User#user{ek_master = not User#user.ek_master}); + _ -> erreur + end + end + )). + + user_by_login_password(Login, Password) -> resultat_transaction(mnesia:transaction( fun() -> @@ -439,6 +475,37 @@ possede_message(Id_user, Id_mess) -> _ -> false end. + +ip_table() -> + resultat_transaction(mnesia:transaction( + fun() -> + qlc:e(qlc:q([IP || IP <- mnesia:table(ip_table)])) + end + )). + + +% Bannie une ip pour un certain temps (en minute). +ban(IP, Duration) -> + mnesia:transaction( + fun() -> + case mnesia:wread({ip_table, IP}) of + [IP_tuple] -> + mnesia:write(IP_tuple#ip_table{ban = now(), ban_duration = Duration}); + _ -> + mnesia:write(#ip_table{ip = IP, ban = now(), ban_duration = Duration}) + end + end + ). + + +update_version(1) -> + mnesia:transform_table( + ip_table, + fun() -> null end, + record_info(fields, ip_table), + ip_table + ). + % Si deux enregistrements consequtifs de la même IP sont fait en moins d'une seconde alors % ip_table.nb_try_register est incrémenté de 1 sinon il est décrémenté de 1 (jusqu'a 0). diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index 1f5faf3..194961e 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -6,11 +6,12 @@ -module(euphorik_protocole). -export([ register/2, - login/1, + login/2, logout/1, profile/1, wait_event/1, put_message/1, + ban/1, erreur/1 ]). @@ -28,6 +29,7 @@ register([{login, Login}, {password, Password}], IP) -> erreur("Login déjà existant"); _ -> User = euphorik_bd:nouveau_user(Login, Password, generer_cookie()), + euphorik_bd:update_ip(User#user.id, IP), json_reponse_login_ok(User) end; true -> @@ -38,6 +40,7 @@ register([], IP) -> Can_register = euphorik_bd:can_register(IP), if Can_register -> User = euphorik_bd:nouveau_user("", generer_cookie()), + euphorik_bd:update_ip(User#user.id, IP), json_reponse_login_ok(User); true -> erreur_register_flood() @@ -48,16 +51,17 @@ erreur_register_flood() -> % Un utilisateur se logge (avec un couple {login, mot de passe}) -login([{login, Login}, {password, Password}]) -> - loginUser(euphorik_bd:user_by_login_password(Login, Password)); +login([{login, Login}, {password, Password}], IP) -> + loginUser(euphorik_bd:user_by_login_password(Login, Password), IP); % Un utilisateur se logge (avec un cookie) -login([{cookie, Cookie}]) -> - loginUser(euphorik_bd:user_by_cookie(Cookie)). +login([{cookie, Cookie}], IP) -> + loginUser(euphorik_bd:user_by_cookie(Cookie), IP). -loginUser({ok, User}) -> +loginUser({ok, User}, IP) -> + euphorik_bd:update_ip(User#user.id, IP), euphorik_bd:update_date_derniere_connexion(User#user.id), json_reponse_login_ok(User); -loginUser(_) -> +loginUser(_, _) -> % ajoute un délais d'attente (TODO : un autre moyen plus élégant ?) receive after 1000 -> erreur("Erreur login") @@ -153,25 +157,26 @@ wait_event(Data) -> {ok, U2} = euphorik_bd:user_by_id(Mess#minichat.auteur_id), U2 end, - {struct, [ - {id, Mess#minichat.id}, - {date, format_date(Mess#minichat.date)}, - {system, Mess#minichat.auteur_id =:= 0}, - {owner, Est_proprietaire}, - {answered, A_repondu_a_message}, - {is_a_reply, Est_une_reponse_a_user}, - {nick, Mess#minichat.pseudo}, - {login, if User_mess =:= inconnu -> Mess#minichat.pseudo; true -> User_mess#user.login end}, - {content, Mess#minichat.contenu}, - {answer_to, {array, lists:map( - fun(Id_mess) -> - {ok, M} = euphorik_bd:message_by_id(Id_mess), - {ok, User_reponse} = euphorik_bd:user_by_mess(M#minichat.id), - {struct, [{id, M#minichat.id}, {nick, M#minichat.pseudo}, {login, User_reponse#user.login}]} - end, - Repond_a - )}} - ]} + {struct, [ + {id, Mess#minichat.id}, + {date, format_date(Mess#minichat.date)}, + {system, Mess#minichat.auteur_id =:= 0}, + {owner, Est_proprietaire}, + {answered, A_repondu_a_message}, + {is_a_reply, Est_une_reponse_a_user}, + {nick, Mess#minichat.pseudo}, + {login, if User_mess =:= inconnu -> Mess#minichat.pseudo; true -> User_mess#user.login end}, + {content, Mess#minichat.contenu}, + {answer_to, {array, lists:map( + fun(Id_mess) -> + {ok, M} = euphorik_bd:message_by_id(Id_mess), + {ok, User_reponse} = euphorik_bd:user_by_mess(M#minichat.id), + {struct, [{id, M#minichat.id}, {nick, M#minichat.pseudo}, {login, User_reponse#user.login}]} + end, + Repond_a + )}}, + {ek_master, User_mess#user.ek_master} + ]} end, Conv ) @@ -217,6 +222,27 @@ put_message( end. +% bannissement d'un utilisateur (son ip est bannie) +ban( + [ + {cookie, Cookie}, + {duration, Duration}, + {user_id, User_id} + ]) -> + % controle que l'utilisateur est un admin + case euphorik_bd:user_by_cookie(Cookie) of + {ok, User = #user{ek_master = true}} -> + case euphorik_bd:user_by_id(User_id) of + {ok, User} -> + euphorik_bd:ban(User#user.last_ip, Duration); + _ -> + erreur("Utilisateur à bannir inconnu") + end; + _ -> + erreur("Utilisateur inconnu ou non ek master") + end. + + % Construit une erreur erreur(Message) -> { @@ -280,6 +306,7 @@ json_reponse_login_ok(User) -> User#user.conversations ) } - } + }, + {ek_master, User#user.ek_master} ] }. diff --git a/modules/erl/euphorik_requests.erl b/modules/erl/euphorik_requests.erl index 6562e52..4af2f7e 100755 --- a/modules/erl/euphorik_requests.erl +++ b/modules/erl/euphorik_requests.erl @@ -20,10 +20,14 @@ tester() -> out(A) -> - %io:format("~p~n~n", [A]), + %io:format("~p~n~n", [A]), + IP = case inet:peername(A#arg.clisock) of + {ok, {Adresse, _Port}} -> Adresse; + _ -> inconnue + end, %inet:setopts(A#arg.clisock, inet:getopts(A#arg.clisock, [active])), {value, {_, Contenu}} = lists:keysearch("action", 1, yaws_api:parse_post(A)), - Ret = traiter_donnees(Contenu, 1), + Ret = traiter_donnees(Contenu, IP), {content, "application/json", Ret}. @@ -37,8 +41,8 @@ traiter_donnees(Contenu, IP) -> % authentification d'un client -traiter_action("authentification", JSON, _) -> - euphorik_protocole:login(JSON); +traiter_action("authentification", JSON, IP) -> + euphorik_protocole:login(JSON, IP); % un client s'enregistre (pseudo + password) traiter_action("register", JSON, IP) -> euphorik_protocole:register(JSON, IP); @@ -50,5 +54,7 @@ traiter_action("wait_event", JSON, _) -> euphorik_protocole:wait_event(JSON); % un utilisateur envoie un message traiter_action("put_message", JSON, _) -> - euphorik_protocole:put_message(JSON). + euphorik_protocole:put_message(JSON); +traiter_action("ban", JSON, _) -> + euphorik_protocole:ban(JSON). \ No newline at end of file diff --git a/modules/include/euphorik_bd.hrl b/modules/include/euphorik_bd.hrl index 6c6cb65..3a8da91 100755 --- a/modules/include/euphorik_bd.hrl +++ b/modules/include/euphorik_bd.hrl @@ -45,7 +45,7 @@ page_principale = 1, % la page de la conversation principale conversations = [], % [{integer(), integer()}], la liste des messages correspondant au conversation ainsi que la page affichée ek_master = false, - last_ip % integer(), undefined si inconnu + last_ip = undefined % integer(), undefined si inconnu }). @@ -53,7 +53,8 @@ -record(ip_table, { ip, % integer() - ban = false, + 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, diff --git a/sessions/erl.session b/sessions/erl.session index 5dda940..dfe47b4 100755 --- a/sessions/erl.session +++ b/sessions/erl.session @@ -1,20 +1,20 @@ # SciTE session file -buffer.1.path=/home/gburri/projets/euphorik/modules/erl/euphorik_minichat.erl -buffer.1.position=360 -buffer.1.current=1 +buffer.1.path=/home/gburri/projets/euphorik/modules/erl/euphorik_minichat_conversation.erl +buffer.1.position=580 -buffer.2.path=/home/gburri/projets/euphorik/modules/erl/euphorik_minichat_conversation.erl +buffer.2.path=/home/gburri/projets/euphorik/modules/erl/euphorik_protocole.erl buffer.2.position=1 -buffer.3.path=/home/gburri/projets/euphorik/modules/erl/euphorik_protocole.erl +buffer.3.path=/home/gburri/projets/euphorik/modules/erl/euphorik_requests.erl buffer.3.position=1 -buffer.4.path=/home/gburri/projets/euphorik/modules/erl/euphorik_requests.erl +buffer.4.path=/home/gburri/projets/euphorik/modules/include/euphorik_bd.hrl buffer.4.position=1 -buffer.5.path=/home/gburri/projets/euphorik/modules/include/euphorik_bd.hrl -buffer.5.position=1 +buffer.5.path=/home/gburri/projets/euphorik/modules/include/euphorik_defines.hrl +buffer.5.position=336 -buffer.6.path=/home/gburri/projets/euphorik/modules/include/euphorik_defines.hrl -buffer.6.position=336 +buffer.6.path=/home/gburri/projets/euphorik/modules/erl/euphorik_bd.erl +buffer.6.position=1 +buffer.6.current=1 diff --git a/sessions/js.session b/sessions/js.session index 4b4bf8a..14853bd 100755 --- a/sessions/js.session +++ b/sessions/js.session @@ -5,6 +5,7 @@ buffer.1.position=22818 buffer.2.path=/home/gburri/projets/euphorik/js/pageMinichat.js buffer.2.position=7496 +buffer.2.current=1 buffer.3.path=/home/gburri/projets/euphorik/js/pageProfile.js buffer.3.position=1 @@ -14,4 +15,15 @@ buffer.4.position=1 buffer.5.path=/home/gburri/projets/euphorik/js/debug.js buffer.5.position=1 -buffer.5.current=1 + +buffer.6.path=/home/gburri/projets/euphorik/css/1/euphorik.css +buffer.6.position=1 + +buffer.7.path=/home/gburri/projets/euphorik/css/1/pageAbout.css +buffer.7.position=1 + +buffer.8.path=/home/gburri/projets/euphorik/css/1/pageMinichat.css +buffer.8.position=1 + +buffer.9.path=/home/gburri/projets/euphorik/css/1/pageProfileRegister.css +buffer.9.position=164