c2cb9846b537865c4faec2cd79644060b46a5af4
[euphorik.git] / euphorik_protocole.erl
1 % coding: utf-8
2 % Ce module gére les différents messages envoyés par le client (javascript) via AJAX.
3 % Les messages donnés ainsi que les réponses sont au format JSON.
4 % @author G.Burri
5
6 -module(euphorik_protocole).
7 -export([
8 register/1,
9 login/1,
10 logout/1,
11 profile/1,
12 wait_event/1,
13 put_message/1,
14 erreur/1
15 ]).
16
17 -include_lib("xmerl/include/xmerl.hrl").
18 -include("../include/euphorik_bd.hrl").
19 -include("../include/euphorik_defines.hrl").
20
21
22 % Une utilisateur s'enregistre avec un tuple {Login, Password}.
23 register([{login, Login}, {password, Password}]) ->
24 case euphorik_minichat:user_by_login(Login) of
25 {ok, _} ->
26 erreur("Login déjà existant");
27 _ ->
28 User = euphorik_minichat:nouveau_user(Login, Password, generer_cookie()),
29 json_reponse_login_ok(User)
30 end;
31 % Enregistrement sans {Login, Password}
32 register([]) ->
33 User = euphorik_minichat:nouveau_user("<nick>", generer_cookie()),
34 json_reponse_login_ok(User).
35
36
37 % Un utilisateur se logge (avec un couple {login, mot de passe})
38 login([{login, Login}, {password, Password}]) ->
39 loginUser(euphorik_minichat:user_by_login_password(Login, Password));
40 % Un utilisateur se logge (avec un cookie)
41 login([{cookie, Cookie}]) ->
42 loginUser(euphorik_minichat:user_by_cookie(Cookie)).
43
44 loginUser({ok, User}) ->
45 euphorik_minichat:update_date_derniere_connexion(User#user.id),
46 json_reponse_login_ok(User);
47 loginUser(_) ->
48 % ajoute un délais d'attente (TODO : un autre moyen plus élégant ?)
49 receive after 1000 ->
50 erreur("Erreur login")
51 end.
52
53
54 % Renvoie un string() représentant un cookie en base 36. Il y a 10^32 possibillités.
55 generer_cookie() ->
56 {A1,A2,A3} = now(),
57 random:seed(A1, A2, A3),
58 erlang:integer_to_list(random:uniform(math:pow(10, 32)), 36).
59
60
61 % Un utilisateur se délogge.
62 logout(_) ->
63 do_nothing.
64
65
66 % Modification du profile.
67 profile(
68 [
69 {cookie, Cookie},
70 {login, Login},
71 {password, Password},
72 {nick, Pseudo},
73 {email, Email},
74 {css, Css},
75 {nick_format, Nick_format_str},
76 {main_page, Main_page},
77 {conversations, {array, Conversations_json}}
78 ]
79 ) ->
80 % est-ce que les messages auquel on répond existent ?
81 Conversations = lists:foldr(
82 fun({struct, [{root, Root}, {page, Page}]}, Acc) ->
83 Message_existe = euphorik_minichat:message_existe(Root),
84 if Message_existe ->
85 [{Root, Page} | Acc];
86 true ->
87 Acc
88 end
89 end,
90 [],
91 Conversations_json
92 ),
93 case euphorik_minichat:set_profile(Cookie, Login, Password, Pseudo, Email, Css, list_to_atom(Nick_format_str), Main_page, Conversations) of
94 ok ->
95 json_reponse_ok();
96 login_deja_pris ->
97 erreur("Login déjà pris");
98 _ ->
99 erreur("Impossible de mettre à jour le profile")
100 end.
101
102
103 % Renvoie les messages appropriés.
104 % last_message id et cookie sont facultatifs
105 % TODO : erreur : {badmatch,false}
106 wait_event(Data) ->
107 Cookie = case lists:keysearch(cookie, 1, Data) of {value, {_, C}} -> C; _ -> inconnu end,
108 Last_message_id = case lists:keysearch(last_message_id, 1, Data) of {value, {_, Id}} -> Id; _ -> 0 end,
109 {value, {_, Message_count}} = lists:keysearch(message_count, 1, Data),
110 Main_page = case lists:keysearch(main_page, 1, Data) of {value, {_, P}} -> P; _ -> 1 end,
111 {value, {_, {array, Conversations_json}}} = lists:keysearch(conversations, 1, Data),
112 Conversations = lists:map(fun({struct, [{root, Racine}, {page, Page}]}) -> {Racine, Page} end, Conversations_json),
113 User = case euphorik_minichat:user_by_cookie(Cookie) of
114 {ok, U} -> U;
115 _ -> inconnu
116 end,
117 {struct, [
118 {reply, "new_message"},
119 {conversations, {array,
120 % accrochez-vous ca va siouxer ;)
121 lists:map(
122 fun({Conv, Plus}) ->
123 {struct, [
124 {last_page, not Plus},
125 {messages, {array,
126 lists:map(
127 fun({Mess, Repond_a}) ->
128 Est_proprietaire = User =/= inconnu andalso User#user.id =:= Mess#minichat.auteur_id,
129 A_repondu_a_message = User =/= inconnu andalso euphorik_minichat:a_repondu_a_message(User#user.id, Mess#minichat.id),
130 Est_une_reponse_a_user = User =/= inconnu andalso euphorik_minichat:est_une_reponse_a_user(User#user.id, Mess#minichat.id),
131 % io:format("Repond_a : ~p~n", [Repond_a]),
132 User_mess =
133 if Mess#minichat.auteur_id =:= 0 ->
134 inconnu;
135 true ->
136 {ok, U2} = euphorik_minichat:user_by_id(Mess#minichat.auteur_id),
137 U2
138 end,
139 {struct, [
140 {id, Mess#minichat.id},
141 {date, format_date(Mess#minichat.date)},
142 {system, Mess#minichat.auteur_id =:= 0},
143 {owner, Est_proprietaire},
144 {answered, A_repondu_a_message},
145 {is_a_reply, Est_une_reponse_a_user},
146 {nick, Mess#minichat.pseudo},
147 {login, if User_mess =:= inconnu -> Mess#minichat.pseudo; true -> User_mess#user.login end},
148 {content, Mess#minichat.contenu},
149 {answer_to, {array, lists:map(
150 fun(Id_mess) ->
151 {ok, M} = euphorik_minichat:message_by_id(Id_mess),
152 {ok, User_reponse} = euphorik_minichat:user_by_mess(M#minichat.id),
153 {struct, [{id, M#minichat.id}, {nick, M#minichat.pseudo}, {login, User_reponse#user.login}]}
154 end,
155 Repond_a
156 )}}
157 ]}
158 end,
159 Conv
160 )
161 }}
162 ]}
163 end,
164 euphorik_minichat_conversation:conversations(
165 Conversations,
166 Message_count,
167 Last_message_id,
168 Main_page
169 )
170 )
171 }}
172 ]}.
173
174
175 % Un utilisateur envoie un message
176 put_message(
177 [
178 {cookie, Cookie},
179 {nick, Nick},
180 {content, Content},
181 {answer_to, {array, Answer_to}}
182 ]
183 ) ->
184 case euphorik_minichat:user_by_cookie(Cookie) of
185 {ok, User} ->
186 Strip_content = string:strip(Content),
187 if (Strip_content =:= []) ->
188 erreur("Message vide");
189 true ->
190 % TODO : non-atomique (update_pseudo+nouveau_message)
191 euphorik_minichat:update_pseudo_user(User#user.id, Nick),
192 case euphorik_minichat:nouveau_message(Strip_content, User#user.id, Answer_to) of
193 erreur -> erreur("Impossible d'ajouter un nouveau message");
194 _ ->
195 json_reponse_ok()
196 end
197 end;
198 _ ->
199 erreur("Utilisateur inconnu")
200 end.
201
202
203 % Construit une erreur
204 erreur(Message) ->
205 {
206 struct, [
207 {reply, "error"},
208 {error_message, Message}
209 ]
210 }.
211
212
213 % Formatage d'une heure
214 % local_time() -> string
215 format_date(Date) ->
216 DateLocal = calendar:now_to_local_time(Date),
217 DateNowLocal = calendar:local_time(),
218 {{Annee, Mois, Jour}, {Heure, Minute, Seconde}} = DateLocal,
219 {{AnneeNow, _, _}, {_, _, _}} = DateNowLocal,
220 Hier = calendar:date_to_gregorian_days(element(1, DateLocal)) =:= calendar:date_to_gregorian_days(element(1, DateNowLocal)) - 1,
221 lists:flatten(
222 if element(1, DateLocal) =:= element(1, DateNowLocal) ->
223 "";
224 Hier ->
225 "Hier ";
226 Annee =:= AnneeNow ->
227 io_lib:format("~2.10.0B/~2.10.0B ", [Jour, Mois]);
228 true ->
229 io_lib:format("~2.10.0B/~2.10.0B/~B ", [Jour, Mois, Annee])
230 end ++
231 io_lib:format("~2.10.0B:~2.10.0B:~2.10.0B", [Heure, Minute, Seconde])
232 ).
233
234
235 %%%%%%%%% <Réponses JSON> %%%%%%%%%
236
237 json_reponse_ok() ->
238 {struct, [{reply, "ok"}]}.
239
240
241 json_reponse_login_ok(User) ->
242 {
243 struct, [
244 {reply, "login"},
245 {status, if (User#user.password =/= []) and (User#user.login =/= []) -> "auth_registered"; true -> "auth_not_registered" end},
246 {cookie, User#user.cookie},
247 {id, User#user.id},
248 {nick, User#user.pseudo},
249 {login, User#user.login},
250 {email, User#user.email},
251 {css, User#user.css},
252 {nick_format, atom_to_list(User#user.nick_format)},
253 {main_page, User#user.page_principale},
254 {conversations,
255 {array,
256 lists:map(
257 fun(C) ->
258 {struct,
259 [
260 {root, element(1, C)},
261 {page, element(2, C)}
262 ]
263 }
264 end,
265 User#user.conversations
266 )
267 }
268 }
269 ]
270 }.
271
272
273 %%%%%%%%% </réponses JSON> %%%%%%%%%