ADD fin de la page admin
[euphorik.git] / modules / erl / euphorik_bd.erl
index a6099fe..9de83fb 100755 (executable)
@@ -19,7 +19,9 @@
    update_date_derniere_connexion/1,
    update_ip/2,
    update_pseudo_user/2,
-   users/0,
+   print_users/0,
+   print_users/1,
+   print_user/1,
    user_by_cookie/1,   
    user_by_id/1,   
    user_by_login/1,
@@ -43,7 +45,7 @@
    possede_message/2,
    
    % ip :
-   ip_table/0,
+   list_ban/0,
    ban/2,
    deban/1,
    est_banni/1,
@@ -52,7 +54,6 @@
    % trolls :
    trolls/0,
    trolls/1,
-   trolls_attente/1,
    put_troll/2,
    mod_troll/2,
    del_troll/1,
@@ -66,9 +67,7 @@
    % utiles :
    resultat_transaction/1\r
 ]).
-
 -import(qlc, [e/1, e/2, q/1, cursor/1]).\r
-\r
 -include("../include/euphorik_bd.hrl").
 -include("../include/euphorik_defines.hrl").\r
 -include_lib("stdlib/include/qlc.hrl").\r
@@ -240,12 +239,56 @@ update_pseudo_user(UserId, Pseudo) ->
       end
    ).
    
-
-% Renvoie tous les users.
-users() ->
+   
+% Affiche N user trié par leur date de dernière connexion.
+% Attention : pas d'index sur ce champs (la date)   
+print_users(N) ->
    resultat_transaction(mnesia:transaction(fun() ->
-      e(q([E || E <- mnesia:table(user)]))
-   end)).   
+      C = cursor(q([E || E <- qlc:keysort(9, mnesia:table(user), [{order, descending}])])),
+      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() ->
+   print_users(all_remaining).
+   
+   
+print_user(User) when is_record(User, user) ->
+   #user{id = Id, pseudo = Pseudo, login = Login, ek_master = Ek_master, date_derniere_connexion = Date} = User,
+   {{Annee, Mois, Jour}, {Heure, Min, _}} = calendar:now_to_local_time(Date),
+   io:format(
+      "~4w : ~10.10..s~10.10..s ~2w.~2.2.0w.~w - ~2wh~2.2.0w~n",
+      [  
+         Id,
+         if Ek_master -> "*"; true -> "" end ++ Pseudo,
+         "(" ++ Login ++ ")",
+         Jour, Mois, Annee, Heure, Min
+      ]
+   );
+% Affichage d'un user en fonction de son login
+print_user(Login) when is_list(Login) ->
+   case 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 user_by_id(Id) of 
+      {ok, User} ->
+         print_user(User);
+      _ ->
+         {erreur, "Id pas trouvé : " ++ integer_to_list(Id)}
+   end.
    
 
 % Est-ce qu'un utilisateur existe en fonction de son cookie ?
@@ -321,7 +364,7 @@ user_by_mess(Id) ->
    \r
    
 % Ajoute un message. Repond_A est une liste d'id auquel le message répond
-% retourne soit l'id du message soit erreur.
+% retourne soit l'id du message soit {erreur, <raison>}.
 nouveau_message(Mess, Auteur_id, Repond_A) ->
    % regarde si les id 'Repond_A' existent
    F = fun() ->   
@@ -329,30 +372,31 @@ nouveau_message(Mess, Auteur_id, Repond_A) ->
       % est-ce que l'auteur existe ?
       Auteur = case e(q([E || E <- mnesia:table(user), E#user.id =:= Auteur_id])) of
          [A] -> A;
-         _ -> throw("L'auteur du message est introuvable")
-      end,
-      if Nb_id_trouve =/= length(Repond_A) -> throw("Un ou plusieurs messages introuvable");
-         true -> ok
+         _ -> {erreur, "L'auteur du message est introuvable"}
       end,
-      % compare les dernière
-      Delta = delta_date_ms(Auteur#user.date_derniere_connexion, now()),
-      Nouvel_indice_flood = Auteur#user.indice_flood + if Delta =< ?DUREE_SPAM -> 2; true -> -1 end,
-      Auteur_maj = Auteur#user{
-         indice_flood = if Nouvel_indice_flood > ?INDICE_SPAM_MAX -> ?INDICE_SPAM_MAX; Nouvel_indice_flood < 0 -> 0; true -> Nouvel_indice_flood end,
-         date_derniere_connexion = now()
-      },
-      % est-ce que l'auteur à trop floodé ?
-      if Auteur#user.indice_flood =/= ?INDICE_SPAM_MAX, Auteur_maj#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->
-         mnesia:write(Auteur#user{indice_flood = Auteur_maj#user.indice_flood}),
-         nouveau_message_sys(Auteur#user.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.");
-      Auteur#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->
-         erreur;
-      true ->     
-         mnesia:write(Auteur_maj),
-         Id = nouvel_id(minichat),
-         inserer_reponses(Id, Repond_A),
-         mnesia:write(#minichat{id=Id, auteur_id=Auteur#user.id, date=now(), pseudo=Auteur#user.pseudo, contenu=Mess}),
-         Id
+      if Nb_id_trouve =/= length(Repond_A) ->
+            {erreur, "Un ou plusieurs messages introuvable"};
+         true ->
+            % comparaison entre la date du dernier poste et maintenant (gestion du flood)
+            Delta = delta_date_ms(Auteur#user.date_derniere_connexion, now()),
+            Nouvel_indice_flood = Auteur#user.indice_flood + if Delta =< ?DUREE_SPAM -> 2; true -> -1 end,
+            Auteur_maj = Auteur#user{
+               indice_flood = if Nouvel_indice_flood > ?INDICE_SPAM_MAX -> ?INDICE_SPAM_MAX; Nouvel_indice_flood < 0 -> 0; true -> Nouvel_indice_flood end,
+               date_derniere_connexion = now()
+            },
+            % est-ce que l'auteur à trop floodé ?
+            if Auteur#user.indice_flood =/= ?INDICE_SPAM_MAX, Auteur_maj#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->
+               mnesia:write(Auteur#user{indice_flood = Auteur_maj#user.indice_flood}),
+               nouveau_message_sys("''" ++ Auteur#user.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.");
+            Auteur#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->
+               {erreur, "Bloqué pour cause de flood"};
+            true ->     
+               mnesia:write(Auteur_maj),
+               Id = nouvel_id(minichat),
+               inserer_reponses(Id, Repond_A),
+               mnesia:write(#minichat{id=Id, auteur_id=Auteur#user.id, date=now(), pseudo=Auteur#user.pseudo, contenu=Mess}),
+               Id
+            end
       end
    end,
    resultat_transaction(mnesia:transaction(F)).
@@ -495,11 +539,23 @@ possede_message(Id_user, Id_mess) ->
       _ -> false
    end.
    
-
-ip_table() ->
+   
+% renvoie la liste des ip bannies
+% liste de {ip, temps_restant(en minutes), Users} ou Users est une liste de {pseudo, login}
+% TODO : déterminer la complexité de cette fonction. (Il n'y a pas d'index sur #user.last_ip)
+list_ban() ->
    resultat_transaction(mnesia:transaction(
       fun() ->
-         e(q([IP || IP <- mnesia:table(ip_table)]))
+         Now = now(),
+         e(q([
+            {
+               IP#ip_table.ip,
+               delta_date_minute(date_plus_minutes(IP#ip_table.ban, IP#ip_table.ban_duration), Now),
+               e(q([{U#user.pseudo, U#user.login} || U <- mnesia:table(user), U#user.last_ip =:= IP#ip_table.ip]))
+            } ||
+            IP <- qlc:keysort(2, mnesia:table(ip_table)),
+            if IP#ip_table.ban =:= undefined -> false; true -> date_plus_minutes(IP#ip_table.ban, IP#ip_table.ban_duration) > Now end
+         ]))
       end
    )).
 
@@ -541,7 +597,7 @@ est_banni(User_id) ->
                if Echeance < Now -> % l'échéance est passée
                      false;
                   true ->
-                     {true, trunc(delta_date_ms(Echeance, Now) / 1000 / 60)}
+                     {true, delta_date_minute(Echeance, Now)}
                end;
             _ ->
                false
@@ -586,7 +642,7 @@ can_register(IP) ->
    )).
    
 
-% Renvoie tous les trolls.
+% Renvoie tous les trolls
 trolls() ->
    resultat_transaction(mnesia:transaction(
       fun() ->
@@ -598,58 +654,11 @@ trolls() ->
 % Renvoie les trolls manquants posté après Last_id.
 trolls(Last_id) ->
    resultat_transaction(mnesia:transaction(
-      e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
+      fun() ->
+         e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
+      end
    )).
    
-   
-% Renvoie les trolls manquants posté après Last_id.
-% Si pas de trolls alors attend un événement tel qu'un ajout, une modification ou une suppression.
-% renvoie :
-%  {mod, Troll}
-% ou {add, [Trolls]}
-% ou {del, Troll_id}
-% ou timeout
-trolls_attente(Last_id) ->
-   case mnesia:subscribe({table, troll, detailed}) of
-      {error, E} = E ->
-         E;
-      _ ->
-         R = case resultat_transaction(mnesia:transaction(
-               fun() ->
-                  e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
-               end
-            )) of
-               [] -> % pas de trolls
-                  attend_evenement_troll();
-               Trolls ->
-                  {add, Trolls}
-         end,
-         mnesia:unsubscribe({table, troll, detailed}),
-         R
-   end.
-   
-attend_evenement_troll() ->
-   % s'il n'y a pas de trolls que l'utilisateur n'a pas connaissance alors on attend un événement
-   receive
-      % cas où un troll est choisit comme courant
-      {mnesia_table_event, {write, troll, Troll, [Old_troll | _], _}} when Old_troll#troll.date_post =:= undefined, Troll#troll.date_post =/= undefined ->
-         {del, Troll#troll.id};
-      {mnesia_table_event, {write, troll, Troll, [_Old_troll | _], _}} ->
-         {mod, Troll};
-      {mnesia_table_event, {write, troll, Troll, [], _}} ->
-         {add, [Troll]};
-      {mnesia_table_event, {delete, troll, {troll, Id}, _, _}} ->
-         {del, Id};
-      {tcp_closed, _} ->
-         exit(normal);
-      _ ->
-         attend_evenement_troll()
-   % 60 minutes de timeout (on ne sais jamais)
-   % Après 60 minutes de connexion, le client doit donc reétablir une connexion
-   after 1000 * 60 * 60 -> 
-      timeout
-   end.
-   
  
  % Renvoie l'id du nouveau troll
  % ou max_troll_reached_per_user si le nombre de troll posté par l'utilisateur max a été atteind
@@ -786,6 +795,10 @@ resultat_transaction({_, T}) ->
 delta_date_ms(D1, D2) ->
    1000000000 * abs(element(1, D1) - element(1, D2)) + 1000 * abs(element(2, D1) - element(2, D2)) + trunc(abs(element(3, D1) - element(3, D2)) / 1000).
 
+% Retourne la différence entre deux timestamp (erlang:now) en minutes
+delta_date_minute(D1, D2) ->
+   trunc(delta_date_ms(D1, D2) / 1000 / 60).
+
 
 % Bizarre, cette fonction n'existe pas dans la stdlib.
 % Pas utilisé mais bon ca me fait de la peine de l'enlever.