margin-top: 40px;\r
}
-#menu {
+ul#menu {
/*
left: 300px;
top: 2px;*/
padding-left: 300px;
/*position: absolute;*/
- height: 25px;
+ height: 23px;
font-size: 11px;
background-color: #000000;
+ list-style-type:none;
}
-#menu div {
+#menu li {
cursor: pointer;
z-index: 20;
float: left;
margin-left: 2px;
background-color: #4f5519;
}
-#menu div.courante {
+#menu li.courante {
background-color: #818c27;
}
-#menu div:hover {
+#menu li:hover {
background-color: #818c27
}
#page.minichat {
+ padding-top: 5px;
padding-right: 0px;
padding-left: 0px
}
== TODO ==\r
\r
-=== v1.0 ===
-\r
+=== v1.0 ===\r
[80%] Un statut "EK" avec plein de privilège à la con. (avoir une petite étoile à coté de son nick ou le nick d'une certaine couleur)\r
* Une page "admin" avec :\r
* Trolls : La liste des trolls proposés. L'admin peut éditer ses propres trolls.\r
* Un kick : l'utilisateur (ip) est kické et bannis pour 15 min\r
* Un ban : l'utilisateur (ip) est kické et bannis pour 3 jours\r
* Modification de la BD -> ajouter une relation "banned_ip"\r
-* Créer un style common puis adapter les CSS (classic et cold -> web2.0)\r
+* Créer un style common puis adapter les CSS (classic et cold -> web2.0)
+* Faire des infos bulles à la facebook\r
* Rendre compatible IE 7 (pfff..)\r
* Mettre un icon (genre sablier ou truc qui tourne à la apple) lorsque le chat se charge (également lors d'un changement de page par exemple)\r
* Simuler un réseau lent\r
indique de mettre à jour la liste d'ips
s -> c
{
- "reply" : "maj_banned_ips"
+ "reply" : "banned_ips_refresh"
}
\r
\r
<div id="container">
<div id="logo"></div>\r
<div id="info" style="display:none" ><div id="icone"></div><div class="fermer" ></div><div class="message" ></div><div class="boutons"></div></div>
- <div id="menu">
- <div class="minichat">chat</div><div class="admin" style="display:none">admin</div><div class="profile"></div><div class="register">register</div><div class="logout">logout</div><div class="about">about</div>\r
- </div>
+ <ul id="menu">
+ <li class="minichat">chat</li><li class="admin" style="display:none">admin</li><li class="profile"></li><li class="register">register</li><li class="logout">logout</li><li class="about">about</li>\r
+ </ul>
<!-- form action="" id="formMenuCss">
<p>
<select id="menuCss">
///////////////////////////////////////////////////////////////////////////////////////////////////\r
\r
/**\r
- * Cette classe regroupe des fonctions utilitaires (helpers).\r
+ * Cette classe regroupe des fonctions utilitaires (helpers).
+ * @formateur est permet de formater les messages affichés à l'aide de messageDialogue (facultatif)\r
*/
-function Util()
+function Util(formateur)
{
$("#info .fermer").click(function(){
$("#info").slideUp(50)
})
+
+ this.formateur = formateur
}
var messageType = {informatif: 0, question: 1, erreur: 2}
* @param type voir 'messageType'. par défaut messageType.informatif\r
* @param les boutons sous la forme d'un objet ou les clefs sont les labels des boutons\r
* et les valeurs les fonctions executées lorsqu'un bouton est activé.
+ * @param formate faut-il formaté le message ? true par défaut
*/
-Util.prototype.messageDialogue = function(message, type, boutons)
+Util.prototype.messageDialogue = function(message, type, boutons, formate)
{
+ var thisUtil = this
+
if (type == undefined)
type = messageType.informatif
+
+ if (formate == undefined)
+ formate = true
if (this.timeoutMessageDialogue != undefined)
clearTimeout(this.timeoutMessageDialogue)
var fermer = function(){$("#info").slideUp(100)}
fermer()
- $("#info .message").html(message)
+ $("#info .message").html(thisUtil.formateur == undefined || !formate ? message : thisUtil.formateur.traitementComplet(message))
switch(type)
{
case messageType.informatif : $("#info #icone").attr("class", "information"); break
///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Classe permettant de formater du texte par exemple pour la substitution des liens dans les
+ * message par "[url]".
+ * TODO : améliorer l'efficacité des méthods notamment lié au smiles.
+ */
function Formateur()
{
this.smiles = conf.smiles\r
*/
Formateur.prototype.traitementComplet = function(M, pseudo)
{
- return this.traiterLiensConv(this.traiterSmiles(this.traiterURL(this.remplacerBalisesHTML(M), pseudo)))
+ return this.traiterLiensConv(this.traiterSmiles(this.traiterURL(this.traiterWikiSyntaxe(this.remplacerBalisesHTML(M)), pseudo)))
}
/**
Formateur.prototype.remplacerBalisesHTML = function(M)
{
- return M.replace(/</g, "<").replace(/>/g, ">")
+ return M.replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """)
}
Formateur.prototype.traiterURL = function(M, pseudo)
}
return M.replace(this.regexUrl, traitementUrl)
}
+
+/**
+ * Formatage en utilisant un sous-ensemble des règles de mediwiki.
+ * par exemple ''italic'' devient <i>italic</i>
+ */
+Formateur.prototype.traiterWikiSyntaxe = function(M)
+{
+ return M.replace(
+ /'''(.*?)'''/g,
+ function(texte, capture)
+ {
+ return "<b>" + capture + "</b>"
+ }
+ ).replace(
+ /''(.*?)''/g,
+ function(texte, capture)
+ {
+ return "<i>" + capture + "</i>"
+ }
+ )
+}
\r
/**\r
* Renvoie une version courte de l'url.\r
$(document).ready(
function()
{
- var util = new Util()
+ var formateur = new Formateur()
+ var util = new Util(formateur)
var client = new Client(util)
- var pages = new Pages()
- var formateur = new Formateur()\r
+ var pages = new Pages()\r
\r
// connexion vers le serveur (utilise un cookie qui traine)\r
client.connexionCookie()
this.formateur = formateur
this.util = util
+ this.pageEvent = new PageEvent("admin", this.util)
+
this.timeoutIDmajIPs = null
}
{
return '<h1>Trolls</h1>\
<p>Un troll est un sujet à débat, en général une question.</p>\
- <p>Chaque semaine un troll est choisit au hasard parmis les trolls proposés et devient le troll de la semaine.</p>\
+ <p>Chaque semaine untrolls troll est choisit au hasard parmis les trolls proposés et devient le troll de la semaine.</p>\
<form action="" id="nouveauTroll">\
<p>\
<input class="troll" name="troll" type="text" maxlength="500" value=""></input>\
var thisPage = this
this.trolls = new Trolls(this.client, this.util, this.formateur)
- this.trolls.rafraichirTrolls()
+ this.waitEvent()
this.majIPs()
PageAdmin.prototype.decharger = function()
{
- this.trolls.pageEvent.stopAttenteCourante()
+ this.pageEvent.stopAttenteCourante()
}
PageAdmin.prototype.posterTroll = function()
)
}
-
/**
* Met à jour la liste des IP bannies.
*/
$(".ban").each(
function()
{
- var ip = $(".ip").html()
+ var ip = $(".ip", this).html()
$(".deban", this).click(
function()
{
- thisPageAdmin.util.messageDialogue("Êtes-vous sur de vouloir débannir l'IP " + ip + " ?", messageType.question,
+ thisPageAdmin.util.messageDialogue("Êtes-vous sur de vouloir débannir l'IP ''" + ip + "'' ?", messageType.question,
{"Oui" : function()
{
thisPageAdmin.deban(ip)
thisPageAdmin.util.messageDialogue(data["error_message"])
break
case "ok" :
- thisPageAdmin.majIPs()
+ // obsolète : plus besoin
+ /* thisPageAdmin.majIPs() */
break
}
}
)
}
+PageAdmin.prototype.waitEvent = function()
+{
+ var thisPageAdmin = this
+
+ this.pageEvent.waitEvent(
+ function() { return { "last_troll" : thisPageAdmin.trolls.dernierTroll }},
+ function(data)
+ {
+ switch (data["reply"])
+ {
+ case "troll_added" :
+ thisPageAdmin.trolls.ajouterTrollEvent(data)
+ break
+ case "troll_modified" :
+ thisPageAdmin.trolls.modifierTrollEvent(data)
+ break
+ case "troll_deleted" :
+ thisPageAdmin.trolls.supprimerTrollEvent(data)
+ break
+ case "banned_ips_refresh" :
+ thisPageAdmin.majIPs()
+ break
+ case "error" :
+ thisTrolls.util.messageDialogue(data["error_message"])
+ break
+ }
+ }
+ )
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////////
this.util = util
this.formateur = formateur
this.dernierTroll = 0
- this.pageEvent = new PageEvent("admin", this.util)
this.trolls = {}
}
+Trolls.prototype.ajouterTrollEvent = function(data)
+{
+ var thisTrolls = this
+
+ var XHTML = ""
+ for (var i = 0; i < data["trolls"].length; i++)
+ {
+ var troll = new Troll(data["trolls"][i]["content"], data["trolls"][i]["author"])
+ var trollId = data["trolls"][i]["troll_id"]
+ thisTrolls.trolls[trollId] = troll
+
+ XHTML +=
+ '<div id="troll' + trollId + '" class="troll">' +
+ '<span class="content">' + thisTrolls.formateur.traitementComplet(troll.content, troll.author) + '</span>' +
+ '<span class="author"> - ' + thisTrolls.formateur.traitementComplet(troll.author) + '</span>' +
+ (data["trolls"][i]["author_id"] == thisTrolls.client.id ? '<span class="editTroll">éditer</span><span class="delTroll">Supprimer</span>' : '') +
+ '</div>'
+ }
+ $("#trolls").append(XHTML)
+ $("#trolls .troll").filter(function(){return parseInt($(this).attr("id").substr(5)) > thisTrolls.dernierTroll}).each(
+ function()
+ {
+ var troll = this
+ var id = parseInt($(this).attr("id").substr(5))
+
+ $("a[@rel*=lightbox]", this).lightBox()
+
+ $(this).keypress(
+ function(e)
+ {
+ if (e.which == 13) // return
+ $(".modifier", this).click()
+ }
+ )
+ $(".delTroll", this).click(
+ function()
+ {
+ thisTrolls.util.messageDialogue(
+ "Êtes-vous sur de vouloir supprimer le troll \"" + thisTrolls.trolls[id].content + "\" ?",
+ messageType.question,
+ {
+ "oui" : function()
+ {
+ thisTrolls.supprimer(id)
+ },
+ "non" : function(){}
+ }
+ )
+ }
+ )
+ $(".editTroll", this).click(
+ function()
+ {
+ $("span", troll).css("display", "none")
+ $(troll).append(
+ '<form><p><input class="content" type="text" size="50" maxlength="500" value="' +
+ thisTrolls.trolls[id].content +
+ '"></input><span class="modifier">modifier</span><span class="annuler">annuler</span></p></form>'
+ )
+ $("form input.content").focus()
+
+ var virerLeFormulaire = function()
+ {
+ $('form', troll).remove()
+ $('span', troll).css("display", "inline")
+ }
+ $("span.modifier", troll).click(
+ function()
+ {
+ var content = $("form input.content", troll).val()
+ virerLeFormulaire()
+ thisTrolls.modifier(id, content)
+ }
+ )
+ $("span.annuler", troll).click( virerLeFormulaire )
+ $("form", troll).submit(function(){ return false})
+ }
+ )
+ }
+ )
+
+ if (data["trolls"].length > 0)
+ thisTrolls.dernierTroll = data["trolls"][data["trolls"].length - 1]["troll_id"]
+}
+
+Trolls.prototype.modifierTrollEvent = function(data)
+{
+ var thisTrolls = this
+ $("#trolls #troll" + data["troll_id"] + " .content").html(thisTrolls.formateur.traitementComplet(data["content"], thisTrolls.trolls[data["troll_id"]].author))
+ $("#trolls #troll" + data["troll_id"] + " a[@rel*=lightbox]").lightBox()
+ thisTrolls.trolls[data["troll_id"]].content = data["content"]
+}
+
+Trolls.prototype.supprimerTrollEvent = function(data)
+{
+ $("#trolls #troll"+data["troll_id"]).remove()
+}
Trolls.prototype.modifier = function(id, content)
{
}
)
}
-
-Trolls.prototype.rafraichirTrolls = function()
-{
- var thisTrolls = this
-
- this.pageEvent.waitEvent(
- function() { return { "last_troll" : thisTrolls.dernierTroll }},
- function(data)
- {
- switch (data["reply"])
- {
- case "troll_added" :
- var XHTML = ""
- for (var i = 0; i < data["trolls"].length; i++)
- {
- var troll = new Troll(data["trolls"][i]["content"], data["trolls"][i]["author"])
- var trollId = data["trolls"][i]["troll_id"]
- thisTrolls.trolls[trollId] = troll
-
- XHTML +=
- '<div id="troll' + trollId + '" class="troll">' +
- '<span class="content">' + thisTrolls.formateur.traitementComplet(troll.content, troll.author) + '</span>' +
- '<span class="author"> - ' + thisTrolls.formateur.traitementComplet(troll.author) + '</span>' +
- (data["trolls"][i]["author_id"] == thisTrolls.client.id ? '<span class="editTroll">éditer</span><span class="delTroll">Supprimer</span>' : '') +
- '</div>'
- }
- $("#trolls").append(XHTML)
- $("#trolls .troll").filter(function(){return parseInt($(this).attr("id").substr(5)) > thisTrolls.dernierTroll}).each(
- function()
- {
- var troll = this
- var id = parseInt($(this).attr("id").substr(5))
-
- $("a[@rel*=lightbox]", this).lightBox()
-
- $(this).keypress(
- function(e)
- {
- if (e.which == 13) // return
- $(".modifier", this).click()
- }
- )
- $(".delTroll", this).click(
- function()
- {
- thisTrolls.util.messageDialogue(
- "Êtes-vous sur de vouloir supprimer le troll \"" + $("#trolls .troll .content").html() + "\" ?",
- messageType.question,
- {
- "oui" : function()
- {
- thisTrolls.supprimer(id)
- },
- "non" : function(){}
- }
- )
- }
- )
- $(".editTroll", this).click(
- function()
- {
- $("span", troll).css("display", "none")
- $(troll).append(
- '<form><p><input class="content" type="text" size="50" maxlength="500" value="' +
- thisTrolls.trolls[id].content +
- '"></input><span class="modifier">modifier</span><span class="annuler">annuler</span></p></form>'
- )
- $("form input.content").focus()
-
- var virerLeFormulaire = function()
- {
- $("form", troll).remove()
- $('span', troll).css("display", "inline")
- }
- $("span.modifier", troll).click(
- function()
- {
- var content = $("form input.content", troll).val()
- virerLeFormulaire()
- thisTrolls.modifier(id, content)
- }
- )
- $("span.annuler", troll).click( virerLeFormulaire )
- $("form", troll).submit(function(){ return false})
- }
- )
- }
- )
-
- if (data["trolls"].length > 0)
- thisTrolls.dernierTroll = data["trolls"][data["trolls"].length - 1]["troll_id"]
- break
- case "troll_modified" :
- $("#trolls #troll" + data["troll_id"] + " .content").html(thisTrolls.formateur.traitementComplet(data["content"], thisTrolls.trolls[data["troll_id"]].author))
- $("#trolls #troll" + data["troll_id"] + " a[@rel*=lightbox]").lightBox()
- thisTrolls.trolls[data["troll_id"]].content = data["content"]
- break
- case "troll_deleted" :
- $("#trolls #troll"+data["troll_id"]).remove()
- break
- case "majIPs" :
- // TODO : mettre l'attente au niveau de la page et pas au niveau des trolls
- // thisPageAdmin.majIPs()
- break
- case "error" :
- thisTrolls.util.messageDialogue(data["error_message"])
- break
- }
- }
- )
-}
\ No newline at end of file
"\">" +
"<div class=\"extraire\">></div>" +
"[<span class=\"date\">" + message.date + "</span>]" +
- "<span class=\"pseudo\"><span class=\"id\" style=\"display: none\">" + message.auteurId + "</span>" + identifiant + "</span>:" +
+ "<span class=\"pseudo\"><span class=\"id\" style=\"display: none\">" + message.auteurId + "</span class=\"ident\">" + identifiant + "</span>:" +
XHTMLrepondA +
- "<span class=\"contenu\">" + (message.systeme ? this.formateur.remplacerBalisesHTML(message.contenu) : this.formateur.traitementComplet(message.contenu, message.pseudo)) + "</span>" +
+ "<span class=\"contenu\">" + this.formateur.traitementComplet(message.contenu, message.pseudo) + "</span>" +
"</div>"
messagePair = !messagePair
$("#conversations #" + this.getId() + " .message").slice(this.nbMessageMax, nbMessagesAffiche).empty()
// ajoute les événements liés à chaque nouveau message
- $("#conversations #" + this.getId() + " .message").filter(function(){return parseInt($(this).attr("id").substr(4), 36) > thisConversation.idDernierMessageAffiche}).each(
+ $("#conversations #" + this.getId() + " .message").filter(function(){ return parseInt($(this).attr("id").substr(4), 36) > thisConversation.idDernierMessageAffiche }).each(
function()
{
$(".lienConv", this).click(
var valCourant = $("input.message").val()
if (valCourant == undefined) valCourant = ""
- var tag = $(".pseudo", this).text() + "{" + idMess + "}" + ">"
+ var tag = $(".pseudo span.ident", this).text() + "{" + idMess + "}" + ">"
if (valCourant.indexOf(tag, 0) == -1)
$("input.message").val(tag + " " + valCourant)
thisConversation.util.setCaretToEnd($("form input.message")[0])
% trolls :
trolls/0,
trolls/1,
- trolls_attente/1,
put_troll/2,
mod_troll/2,
del_troll/1,
% est-ce que l'auteur à trop floodé ?
if Auteur#user.indice_flood =/= ?INDICE_SPAM_MAX, Auteur_maj#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->
mnesia:write(Auteur#user{indice_flood = Auteur_maj#user.indice_flood}),
- nouveau_message_sys(Auteur#user.pseudo ++ if Auteur#user.login =/= [] -> " (" ++ Auteur#user.login ++ ")"; true -> "" end ++ " est bloqué pour " ++ integer_to_list(trunc(?DUREE_BLOCAGE_SPAM / 1000)) ++ " secondes pour cause de flood.");
+ nouveau_message_sys("''" ++ Auteur#user.pseudo ++ if Auteur#user.login =/= [] -> " (" ++ Auteur#user.login ++ ")"; true -> "" end ++ "'' est bloqué pour " ++ integer_to_list(trunc(?DUREE_BLOCAGE_SPAM / 1000)) ++ " secondes pour cause de flood.");
Auteur#user.indice_flood =:= ?INDICE_SPAM_MAX, Delta =< ?DUREE_BLOCAGE_SPAM ->
{erreur, "Bloqué pour cause de flood"};
true ->
% Renvoie les trolls manquants posté après Last_id.
trolls(Last_id) ->
resultat_transaction(mnesia:transaction(
- e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
+ fun() ->
+ e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
+ end
)).
-
-% Renvoie les trolls manquants posté après Last_id.
-% Si pas de trolls alors attend un événement tel qu'un ajout, une modification ou une suppression.
-% renvoie :
-% {mod, Troll}
-% ou {add, [Trolls]}
-% ou {del, Troll_id}
-% ou timeout
-trolls_attente(Last_id) ->
- case mnesia:subscribe({table, troll, detailed}) of
- {error, E} = E ->
- E;
- _ ->
- R = case resultat_transaction(mnesia:transaction(
- fun() ->
- e(q([T || T <- qlc:keysort(2, mnesia:table(troll)), T#troll.id > Last_id, T#troll.date_post =:= undefined]))
- end
- )) of
- [] -> % pas de trolls
- attend_evenement_troll();
- Trolls ->
- {add, Trolls}
- end,
- mnesia:unsubscribe({table, troll, detailed}),
- R
- end.
-
-attend_evenement_troll() ->
- % s'il n'y a pas de trolls que l'utilisateur n'a pas connaissance alors on attend un événement
- receive
- % cas où un troll est choisit comme courant
- {mnesia_table_event, {write, troll, Troll, [Old_troll | _], _}} when Old_troll#troll.date_post =:= undefined, Troll#troll.date_post =/= undefined ->
- {del, Troll#troll.id};
- {mnesia_table_event, {write, troll, Troll, [_Old_troll | _], _}} ->
- {mod, Troll};
- {mnesia_table_event, {write, troll, Troll, [], _}} ->
- {add, [Troll]};
- {mnesia_table_event, {delete, troll, {troll, Id}, _, _}} ->
- {del, Id};
- {tcp_closed, _} ->
- exit(normal);
- _ ->
- attend_evenement_troll()
- % 60 minutes de timeout (on ne sais jamais)
- % Après 60 minutes de connexion, le client doit donc reétablir une connexion
- after 1000 * 60 * 60 ->
- timeout
- end.
-
% Renvoie l'id du nouveau troll
% ou max_troll_reached_per_user si le nombre de troll posté par l'utilisateur max a été atteind
R
end;
wait_event([{page, "admin"}, {last_troll, Last_troll}]) ->
- case euphorik_bd:trolls_attente(Last_troll) of
+ case wait_event_page_admin(Last_troll) of
+ banned_ips_refresh ->
+ {struct,
+ [
+ {reply, "banned_ips_refresh"}
+ ]
+ };
{mod, Troll} ->
{struct,
[
% Après 60 minutes de connexion, le client doit donc reétablir une connexion
after 1000 * 60 * 60 ->
timeout
- end.
+ end.
+
+
+% Attent un événement concernant la page admin
+% Renvoie les trolls manquants posté après Last_id ou banned_ips_refresh.
+% Si pas de trolls alors attend un événement tel qu'un ajout, une modification ou une suppression.
+% renvoie :
+% {mod, Troll}
+% ou {add, [Trolls]}
+% ou {del, Troll_id}
+% ou banned_ips_refresh
+% ou timeout
+wait_event_page_admin(Last_id) ->
+ case {mnesia:subscribe({table, troll, detailed}), mnesia:subscribe({table, ip_table, detailed})} of
+ {{error, E}, _ } -> E;
+ {_, {error, E}} -> E;
+ _ ->
+ R = case euphorik_bd:trolls(Last_id) of
+ [] -> % pas de trolls
+ wait_event_page_admin();
+ Trolls ->
+ {add, Trolls}
+ end,
+ mnesia:unsubscribe({table, troll, detailed}),
+ mnesia:unsubscribe({table, ip_table, detailed}),
+ R
+ end.
+
+wait_event_page_admin() ->
+ % s'il n'y a pas de trolls que l'utilisateur n'a pas connaissance alors on attend un événement
+ receive
+ % cas où un troll est choisit comme courant
+ {mnesia_table_event, {write, troll, Troll, [Old_troll | _], _}}
+ when Old_troll#troll.date_post =:= undefined, Troll#troll.date_post =/= undefined ->
+ {del, Troll#troll.id};
+ {mnesia_table_event, {write, troll, Troll, [_Old_troll | _], _}} ->
+ {mod, Troll};
+ {mnesia_table_event, {write, troll, Troll, [], _}} ->
+ {add, [Troll]};
+ {mnesia_table_event, {delete, troll, {troll, Id}, _, _}} ->
+ {del, Id};
+ {mnesia_table_event, {write, ip_table, IP, [Old_IP | _], _}}
+ when Old_IP#ip_table.ban =/= IP#ip_table.ban; Old_IP#ip_table.ban_duration =/= IP#ip_table.ban_duration ->
+ banned_ips_refresh;
+ {tcp_closed, _} ->
+ exit(normal);
+ _ ->
+ wait_event_page_admin()
+ % 60 minutes de timeout (on ne sais jamais)
+ % Après 60 minutes de connexion, le client doit donc reétablir une connexion
+ after 1000 * 60 * 60 ->
+ timeout
+ end.
% Un utilisateur envoie un message
erreur("Il n'est pas possible de s'auto bannir");
{ok, User2 = #user{ek_master = false}} ->
euphorik_bd:ban(User2#user.last_ip, Duration),
- euphorik_bd:nouveau_message_sys(lists:flatten(io_lib:format("~s ~s est ~s pour ~s.~s",
+ euphorik_bd:nouveau_message_sys(lists:flatten(io_lib:format("''~s~s'' est ~s pour ~s.~s",
[
User2#user.pseudo,
- if User2#user.login =:= [] -> ""; true -> "(" ++ User2#user.login ++ ")" end,
+ if User2#user.login =:= [] -> ""; true -> " (" ++ User2#user.login ++ ")" end,
if Duration =< 15 -> "kické"; true -> "banni" end,
format_minutes(Duration),
if Reason =/= [] -> " - Raison: " ++ Reason; true -> "" end ++ "."
if Minutes == 0 ->
"";
true ->
- integer_to_list(Minutes) ++ " minute" ++ if Minutes > 1 -> "s"; true -> "" end
+ " " ++ integer_to_list(Minutes) ++ " minute" ++ if Minutes > 1 -> "s"; true -> "" end
end.
\r