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.
6 -module(euphorik_protocole
).
18 -include_lib("xmerl/include/xmerl.hrl").
19 -include("../include/euphorik_bd.hrl").
20 -include("../include/euphorik_defines.hrl").
23 % Une utilisateur s'enregistre avec un tuple {Login, Password}.
24 register([{login
, Login
}, {password
, Password
}], IP
) ->
25 Can_register
= euphorik_bd:can_register(IP
),
27 case euphorik_bd:user_by_login(Login
) of
29 erreur("Login déjà existant");
31 User
= euphorik_bd:nouveau_user(Login
, Password
, generer_cookie()),
32 euphorik_bd:update_ip(User#user
.id
, IP
),
33 json_reponse_login_ok(User
)
36 erreur_register_flood()
38 % Enregistrement sans {Login, Password}
40 Can_register
= euphorik_bd:can_register(IP
),
42 User
= euphorik_bd:nouveau_user("<nick>", generer_cookie()),
43 euphorik_bd:update_ip(User#user
.id
, IP
),
44 json_reponse_login_ok(User
);
46 erreur_register_flood()
49 erreur_register_flood() ->
50 erreur("Trop de register (flood)").
53 % Un utilisateur se logge (avec un couple {login, mot de passe})
54 login([{login
, Login
}, {password
, Password
}], IP
) ->
55 loginUser(euphorik_bd:user_by_login_password(Login
, Password
), IP
);
56 % Un utilisateur se logge (avec un cookie)
57 login([{cookie
, Cookie
}], IP
) ->
58 loginUser(euphorik_bd:user_by_cookie(Cookie
), IP
).
60 loginUser({ok
, User
}, IP
) ->
61 euphorik_bd:update_ip(User#user
.id
, IP
),
62 euphorik_bd:update_date_derniere_connexion(User#user
.id
),
63 json_reponse_login_ok(User
);
65 % ajoute un délais d'attente (TODO : un autre moyen plus élégant ?)
67 erreur("Erreur login")
71 % Renvoie un string() représentant un cookie en base 36. Il y a 10^32 possibillités.
74 random:seed(A1
, A2
, A3
),
75 erlang:integer_to_list(random:uniform(math:pow(10, 32)), 36).
78 % Un utilisateur se délogge.
83 % Modification du profile.
92 {nick_format
, Nick_format_str
},
93 {main_page
, Main_page
},
94 {conversations
, {array
, Conversations_json
}}
97 % est-ce que les messages auquel on répond existent ?
98 Conversations
= lists:foldr(
99 fun({struct
, [{root
, Root
}, {page
, Page
}]}, Acc
) ->
100 Message_existe
= euphorik_bd:message_existe(Root
),
102 [{Root
, Page
} | Acc
];
110 case euphorik_bd:set_profile(Cookie
, Login
, Password
, Pseudo
, Email
, Css
, list_to_atom(Nick_format_str
), Main_page
, Conversations
) of
114 erreur("Login déjà pris");
116 erreur("Impossible de mettre à jour le profile")
120 % Renvoie les messages appropriés.
121 % last_message id et cookie sont facultatifs
123 Cookie
= case lists:keysearch(cookie
, 1, Data
) of {value
, {_
, C
}} -> C
; _
-> inconnu
end,
124 Last_message_id
= case lists:keysearch(last_message_id
, 1, Data
) of {value
, {_
, Id
}} -> Id
; _
-> 0 end,
125 {value
, {_
, Message_count
}} = lists:keysearch(message_count
, 1, Data
),
126 Main_page
= case lists:keysearch(main_page
, 1, Data
) of {value
, {_
, P
}} -> P
; _
-> 1 end,
127 {value
, {_
, {array
, Conversations_json
}}} = lists:keysearch(conversations
, 1, Data
),
128 Conversations
= lists:map(
129 fun({struct
, [{root
, Racine
}, {page
, Page
} | Reste
]}) ->
130 Last_mess_conv
= case Reste
of [{last_message_id
, L
}] -> L
; _
-> 0 end,
131 {Racine
, Page
, Last_mess_conv
}
135 User
= case euphorik_bd:user_by_cookie(Cookie
) of
140 {reply
, "new_message"},
141 {conversations
, {array
,
142 % accrochez-vous ca va siouxer ;)
146 {last_page
, not Plus
},
149 fun({Mess
, Repond_a
}) ->
150 Est_proprietaire
= User
=/= inconnu andalso User#user
.id
=:= Mess#minichat
.auteur_id
,
151 A_repondu_a_message
= User
=/= inconnu andalso
euphorik_bd:a_repondu_a_message(User#user
.id
, Mess#minichat
.id
),
152 Est_une_reponse_a_user
= User
=/= inconnu andalso
euphorik_bd:est_une_reponse_a_user(User#user
.id
, Mess#minichat
.id
),
153 {ok
, User_mess
} = euphorik_bd:user_by_id(Mess#minichat
.auteur_id
),
155 {id
, Mess#minichat
.id
},
156 {user_id
, User_mess#user
.id
},
157 {date, format_date(Mess#minichat
.date)},
158 {system
, Mess#minichat
.auteur_id
=:= 0},
159 {owner
, Est_proprietaire
},
160 {answered
, A_repondu_a_message
},
161 {is_a_reply
, Est_une_reponse_a_user
},
162 {nick
, Mess#minichat
.pseudo
},
163 {login
, User_mess#user
.login
},
164 {content
, Mess#minichat
.contenu
},
165 {answer_to
, {array
, lists:map(
167 {ok
, M
} = euphorik_bd:message_by_id(Id_mess
),
168 {ok
, User_reponse
} = euphorik_bd:user_by_mess(M#minichat
.id
),
169 {struct
, [{id
, M#minichat
.id
}, {nick
, M#minichat
.pseudo
}, {login
, User_reponse#user
.login
}]}
173 {ek_master
, User_mess#user
.ek_master
}
181 euphorik_minichat_conversation:conversations(
192 % Un utilisateur envoie un message
198 {answer_to
, {array
, Answer_to
}}
201 case euphorik_bd:user_by_cookie(Cookie
) of
203 case euphorik_bd:est_banni(User#user
.id
) of
204 {true
, Temps_restant
} ->
205 erreur("Vous êtes banni pour encore " ++ format_minutes(Temps_restant
));
207 Strip_content
= string:strip(Content
),
208 if Strip_content
=:= [] ->
209 erreur("Message vide");
211 % TODO : non-atomique (update_pseudo+nouveau_message)
212 euphorik_bd:update_pseudo_user(User#user
.id
, Nick
),
213 case euphorik_bd:nouveau_message(Strip_content
, User#user
.id
, Answer_to
) of
214 erreur
-> erreur("Impossible d'ajouter un nouveau message");
221 erreur("Utilisateur inconnu")
225 % Formatage de minutes.
226 % par exemple : "1min", "45min", "1h23min", "1jour 2h34min"
227 format_minutes(Min
) ->
228 Jours
= Min
div (60 * 24),
229 Heures
= Min
rem (60 * 24) div
60,
230 Minutes
= Min
rem (60),
231 if Jours
=/= 0 -> integer_to_list(Jours
) ++ "Jour" ++ if Jours
> 1 -> "s"; true
-> "" end ++ " "; true
-> "" end ++
232 if Heures
=/= 0 -> integer_to_list(Heures
) ++ "h"; true
-> "" end ++
233 lists:flatten(io_lib:format(if Jours
=:= 0, Heures
=:= 0 -> "~w"; true
-> "~2.2.0w" end, [Minutes
])) ++ "min".
236 % bannissement d'un utilisateur (son ip est bannie)
240 {duration
, Duration
},
243 % controle que l'utilisateur est un admin
244 case euphorik_bd:user_by_cookie(Cookie
) of
245 {ok
, User1
= #user
{ek_master
= true
}} ->
246 case euphorik_bd:user_by_id(User_id
) of
248 erreur("Il n'est pas possible de s'auto bannir");
249 {ok
, User2
= #user
{ek_master
= false
}} ->
250 euphorik_bd:ban(User2#user
.last_ip
, Duration
),
251 euphorik_bd:nouveau_message_sys(lists:flatten(io_lib:format("~s ~s est ~s pour ~s",
254 if User2#user
.login
=:= [] -> ""; true
-> "(" ++ User2#user
.login
++ ")" end,
255 if Duration
=< 15 -> "kické"; true
-> "banni" end,
256 format_minutes(Duration
)
261 erreur("L'utilisateur est lui même un ekMaster");
263 erreur("Utilisateur à bannir inconnu")
266 erreur("Utilisateur inconnu ou non ek master")
270 % Construit une erreur
275 {error_message
, Message
}
280 % Formatage d'une heure
281 % local_time() -> string
283 DateLocal
= calendar:now_to_local_time(Date
),
284 DateNowLocal
= calendar:local_time(),
285 {{Annee
, Mois
, Jour
}, {Heure
, Minute
, Seconde
}} = DateLocal
,
286 {{AnneeNow
, _
, _
}, {_
, _
, _
}} = DateNowLocal
,
287 Hier
= calendar:date_to_gregorian_days(element(1, DateLocal
)) =:= calendar:date_to_gregorian_days(element(1, DateNowLocal
)) - 1,
289 if element(1, DateLocal
) =:= element(1, DateNowLocal
) ->
293 Annee
=:= AnneeNow
->
294 io_lib:format("~2.10.0B/~2.10.0B ", [Jour
, Mois
]);
296 io_lib:format("~2.10.0B/~2.10.0B/~B ", [Jour
, Mois
, Annee
])
298 io_lib:format("~2.10.0B:~2.10.0B:~2.10.0B", [Heure
, Minute
, Seconde
])
303 {struct
, [{reply
, "ok"}]}.
306 json_reponse_login_ok(User
) ->
310 {status
, if (User#user
.password
=/= []) and (User#user
.login
=/= []) -> "auth_registered"; true
-> "auth_not_registered" end},
311 {cookie
, User#user
.cookie
},
313 {nick
, User#user
.pseudo
},
314 {login
, User#user
.login
},
315 {email
, User#user
.email
},
316 {css
, User#user
.css
},
317 {nick_format
, atom_to_list(User#user
.nick_format
)},
318 {main_page
, User#user
.page_principale
},
325 {root
, element(1, C
)},
326 {page
, element(2, C
)}
330 User#user
.conversations
334 {ek_master
, User#user
.ek_master
}