% coding: utf-8 % Ce module gére les différents messages envoyés par le client (javascript) via AJAX. % Les messages donnés ainsi que les réponses sont au format JSON. % @author G.Burri -module(euphorik_protocole). -export([ register/1, login/1, logout/1, profile/1, wait_event/1, put_message/1, erreur/1 ]). -include_lib("xmerl/include/xmerl.hrl"). -include("../include/euphorik_bd.hrl"). -include("../include/euphorik_defines.hrl"). % Une utilisateur s'enregistre avec un tuple {Login, Password}. register([{login, Login}, {password, Password}]) -> case euphorik_minichat:user_by_login(Login) of {ok, _} -> erreur("Login déjà existant"); _ -> User = euphorik_minichat:nouveau_user(Login, Password, generer_cookie()), json_reponse_login_ok(User) end; % Enregistrement sans {Login, Password} register([]) -> User = euphorik_minichat:nouveau_user("", generer_cookie()), json_reponse_login_ok(User). % Un utilisateur se logge (avec un couple {login, mot de passe}) login([{login, Login}, {password, Password}]) -> loginUser(euphorik_minichat:user_by_login_password(Login, Password)); % Un utilisateur se logge (avec un cookie) login([{cookie, Cookie}]) -> loginUser(euphorik_minichat:user_by_cookie(Cookie)). loginUser({ok, User}) -> euphorik_minichat:update_date_derniere_connexion(User#user.id), json_reponse_login_ok(User); loginUser(_) -> erreur("Erreur login"). % Renvoie un string() représentant un cookie en base 36. Il y a 10^32 possibillités. generer_cookie() -> {A1,A2,A3} = now(), random:seed(A1, A2, A3), erlang:integer_to_list(random:uniform(math:pow(10, 32)), 36). % Un utilisateur se délogge. logout(_) -> do_nothing. % Modification du profile. profile( [ {cookie, Cookie}, {login, Login}, {password, Password}, {nick, Pseudo}, {email, Email}, {css, Css}, {main_page, Main_page}, {conversations, Conversations_json} ] ) -> % est-ce que les messages auquel on répond existent ? Conversations = lists:foldr( fun([struct, {root, Root}, {page, Page}], Acc) -> Message_existe = euphorik_minichat:message_existe(Root), if Message_existe -> [{Root, Page} | Acc]; true -> Acc end end, [], Conversations_json ), case euphorik_minichat:set_profile(Cookie, Login, Password, Pseudo, Email, Css, Main_page, Conversations) of ok -> json_reponse_ok(); login_deja_pris -> erreur("Login déjà pris"); _ -> erreur("Impossible de mettre à jour le profile") end. % Renvoie les messages appropriés. % last_message id et cookie sont facultatifs % TODO : erreur : {badmatch,false} wait_event(Data) -> Cookie = case lists:keysearch(cookie, 1, Data) of {value, {_, C}} -> C; _ -> inconnu end, Last_message_id = case lists:keysearch(last_message_id, 1, Data) of {value, {_, Id}} -> Id; _ -> 0 end, {value, {_, Message_count}} = lists:keysearch(message_count, 1, Data), Main_page = case lists:keysearch(main_page, 1, Data) of {value, {_, P}} -> P; _ -> 1 end, {value, {_, {array, Conversations_json}}} = lists:keysearch(conversations, 1, Data), Conversations = lists:map(fun({struct, [{racine, Racine}, {page, Page}]}) -> {Racine, Page} end, Conversations_json), User = case euphorik_minichat:user_by_cookie(Cookie) of {ok, U} -> U; _ -> inconnu end, {struct, [ {reply, "new_message"}, {conversations, {array, % accrochez-vous ca va siouxer ;) lists:map( fun({Conv, Plus}) -> {struct, [ {last_page, not Plus}, {messages, {array, lists:map( fun({Mess, Repond_a}) -> Est_proprietaire = User =/= inconnu andalso User#user.id =:= Mess#minichat.auteur_id, A_repondu_a_message = User =/= inconnu andalso euphorik_minichat:a_repondu_a_message(User#user.id, Mess#minichat.id), Est_une_reponse_a_user = User =/= inconnu andalso euphorik_minichat:est_une_reponse_a_user(User#user.id, Mess#minichat.id), % io:format("Repond_a : ~p~n", [Repond_a]), User_mess = if Mess#minichat.auteur_id =:= 0 -> inconnu; true -> {ok, U2} = euphorik_minichat: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_minichat:message_by_id(Id_mess), {ok, User_reponse} = euphorik_minichat:user_by_mess(M#minichat.id), {struct, [{id, M#minichat.id}, {nick, M#minichat.pseudo}, {login, User_reponse#user.login}]} end, Repond_a )}} ]} end, Conv ) }} ]} end, euphorik_minichat_conversation:conversations( Conversations, Message_count, Last_message_id, Main_page ) ) }} ]}. % Un utilisateur envoie un message put_message( [ {cookie, Cookie}, {nick, Nick}, {content, Content}, {answer_to, {array, Answer_to}} ] ) -> case euphorik_minichat:user_by_cookie(Cookie) of {ok, User} -> Strip_content = string:strip(Content), if (Strip_content =:= []) -> erreur("Message vide"); true -> % TODO : non-atomique (update_pseudo+nouveau_message) euphorik_minichat:update_pseudo_user(User#user.id, Nick), case euphorik_minichat:nouveau_message(Strip_content, User#user.id, Answer_to) of erreur -> erreur("Impossible d'ajouter un nouveau message"); _ -> json_reponse_ok() end end; _ -> erreur("Utilisateur inconnu") end. % Construit une erreur erreur(Message) -> { struct, [ {reply, "error"}, {error_message, Message} ] }. % Formatage d'une heure % local_time() -> string format_date(Date) -> DateLocal = calendar:now_to_local_time(Date), DateNowLocal = calendar:local_time(), {{Annee, Mois, Jour}, {Heure, Minute, Seconde}} = DateLocal, {{AnneeNow, _, _}, {_, _, _}} = DateNowLocal, Hier = calendar:date_to_gregorian_days(element(1, DateLocal)) =:= calendar:date_to_gregorian_days(element(1, DateNowLocal)) - 1, lists:flatten( if element(1, DateLocal) =:= element(1, DateNowLocal) -> ""; Hier -> "Hier "; Annee =:= AnneeNow -> io_lib:format("~2.10.0B/~2.10.0B ", [Jour, Mois]); true -> io_lib:format("~2.10.0B/~2.10.0B/~B ", [Jour, Mois, Annee]) end ++ io_lib:format("~2.10.0B:~2.10.0B:~2.10.0B", [Heure, Minute, Seconde]) ). %%%%%%%%% %%%%%%%%% json_reponse_ok() -> {struct, [{reply, "ok"}]}. json_reponse_login_ok(User) -> { struct, [ {reply, "login"}, {status, if (User#user.password =/= []) and (User#user.login =/= []) -> "auth_registered"; true -> "auth_not_registered" end}, {cookie, User#user.cookie}, {id, User#user.id}, {nick, User#user.pseudo}, {login, User#user.login}, {email, User#user.email}, {css, User#user.css}, {main_page, User#user.page_principale}, {conversations, {array, lists:map( fun(C) -> {struct, {root, element(1, C)}, {page, element(2, C)} } end, User#user.conversations ) } } ] }. %%%%%%%%% %%%%%%%%%