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