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