Ajout du système de discussion et fixe des quelques bugs

This commit is contained in:
Pierre-Lin Bonnemaison 2015-08-17 02:30:09 +02:00
parent 1a4837a7a3
commit db1b5c35d8
12 changed files with 699 additions and 6 deletions

232
controllers/discussions.php Executable file
View File

@ -0,0 +1,232 @@
<?php
/**
* Page des discussions
*/
class discussions extends Controller
{
/**
* Cette fonction est appelée avant toute les autres :
* Elle vérifie que l'utilisateur est bien connecté
* @return void;
*/
public function before()
{
internalTools::verifyConnect();
}
/**
* Cette fonction retourne toutes les discussions, sous forme d'un tableau permettant l'administration de ces contacts
*/
public function byDefault()
{
//Creation de l'object de base de données
global $db;
//Recupération des nombres des 4 panneaux d'accueil
$discussions = $db->getDiscussions();
foreach ($discussions as $key => $discussion)
{
if (!$contacts = $db->getFromTableWhere('contacts', ['number' => $discussion['number']]))
{
continue;
}
$discussions[$key]['contact'] = $contacts[0]['name'];
}
$this->render('discussions/default', array(
'discussions' => $discussions,
));
}
/**
* Cette fonction permet d'afficher la discussion avec un numero
* @param string $number : La numéro de téléphone avec lequel on discute
*/
public function show ($number)
{
global $db;
$contact = '';
if ($contacts = $db->getFromTableWhere('contacts', ['number' => $number]))
{
$contact = $contacts[0]['name'];
}
$this->render('discussions/show', array(
'number' => $number,
'contact' => $contact,
));
}
/**
* Cette fonction récupère l'ensemble des messages pour un numéro, recçus, envoyés, en cours
* @param string $number : Le numéro cible
* @param string $transactionId : Le numéro unique de la transaction ajax (sert à vérifier si la requete doit être prise en compte)
*/
function getmessages($number, $transactionId)
{
global $db;
$now = new DateTime();
$now = $now->format('Y-m-d H:i:s');
$sendeds = $db->getFromTableWhere('sendeds', ['target' => $number], 'at');
$receiveds = $db->getFromTableWhere('receiveds', ['send_by' => $number], 'at');
$scheduleds = $db->getScheduledsBeforeDateForNumber($now, $number);
$messages = [];
foreach ($sendeds as $sended)
{
$messages[] = array(
'date' => $sended['at'],
'text' => $sended['content'],
'type' => 'sended',
);
}
foreach ($receiveds as $received)
{
$messages[] = array(
'date' => $received['at'],
'text' => $received['content'],
'type' => 'received',
);
}
foreach ($scheduleds as $scheduled)
{
$messages[] = array(
'date' => $scheduled['at'],
'text' => $scheduled['content'],
'type' => 'inprogress',
);
}
//On va trier le tableau des messages
usort($messages, function($a, $b) {
return strtotime($a["date"]) - strtotime($b["date"]);
});
echo json_encode(['transactionId' => $transactionId, 'messages' => $messages]);
return true;
}
/**
* Cette fonction permet d'envoyer facilement un sms à un numéro donné
* @param string $csrf : Le jeton csrf
* @param string $_POST['content'] : Le contenu du SMS
* @param string $_POST['numbers'] : Un tableau avec le numero des gens auxquel envoyer le sms
* @return json : Le statut de l'envoi
*/
function send ($csrf)
{
global $db;
$return = ['success' => true, 'message' => ''];
//On vérifie que le jeton csrf est bon
if (!internalTools::verifyCSRF($csrf))
{
$return['success'] = false;
$return['message'] = 'Jeton CSRF invalide';
echo json_encode($return);
return false;
}
$now = new DateTime();
$now = $now->format('Y-m-d H:i:s');
$_POST['date'] = $now;
$scheduleds = new scheduleds();
if (!$scheduleds->create('', true, true))
{
$return['success'] = false;
$return['message'] = 'Impossible de créer le SMS';
echo json_encode($return);
return false;
}
$return['id'] = $_SESSION['discussion_wait_progress'][count($_SESSION['discussion_wait_progress']) - 1];
echo json_encode($return);
return true;
}
/**
* Cette fonction retourne les id des sms qui sont envoyés
* @return json : Tableau des ids des sms qui sont envoyés
*/
function checksendeds ()
{
global $db;
$_SESSION['discussion_wait_progress'] = isset($_SESSION['discussion_wait_progress']) ? $_SESSION['discussion_wait_progress'] : [];
$scheduleds = $db->getScheduledsIn($_SESSION['discussion_wait_progress']);
//On va chercher à chaque fois si on a trouvé le sms. Si ce n'est pas le cas c'est qu'il a été envoyé
$sendeds = [];
foreach ($_SESSION['discussion_wait_progress'] as $key => $id)
{
$found = false;
foreach ($scheduleds as $scheduled)
{
if ($id == $scheduled['id'])
{
$found = true;
}
}
if (!$found)
{
unset($_SESSION['discussion_wait_progress'][$key]);
$sendeds[] = $id;
}
}
echo json_encode($sendeds);
return true;
}
/**
* Cette fonction retourne les messages reçus pour un numéro après la date $_SESSION['discussion_last_checkreceiveds']
* @param string $number : Le numéro de téléphone pour lequel on veux les messages
* @return json : Un tableau avec les messages
*/
function checkreceiveds ($number)
{
global $db;
$now = new DateTime();
$now = $now->format('Y-m-d H:i');
$_SESSION['discussion_last_checkreceiveds'] = isset($_SESSION['discussion_last_checkreceiveds']) ? $_SESSION['discussion_last_checkreceiveds'] : $now;
$receiveds = $db->getReceivedsSinceForNumberOrderByDate($_SESSION['discussion_last_checkreceiveds'], $number);
//On va gérer le cas des messages en double en stockant ceux déjà reçus et en eliminant les autres
$_SESSION['discussion_already_receiveds'] = isset($_SESSION['discussion_already_receiveds']) ? $_SESSION['discussion_already_receiveds'] : [];
foreach ($receiveds as $key => $received)
{
//Sms jamais recu
if (array_search($received['id'], $_SESSION['discussion_already_receiveds']) === false)
{
$_SESSION['discussion_already_receiveds'][] = $received['id'];
continue;
}
//Sms déjà reçu => on le supprime des resultats
unset($receiveds[$key]);
}
//On met à jour la date de dernière verif
$_SESSION['discussion_last_checkreceiveds'] = $now;
echo json_encode($receiveds);
}
}

View File

@ -134,7 +134,10 @@
$now = new DateTime(); $now = new DateTime();
$now = $now->format('Y-m-d H:i:s'); $now = $now->format('Y-m-d H:i:s');
//On peut maintenant ajouter le SMS //On peut maintenant ajouter le SMS
$db->insertIntoTable('sendeds', ['at' => $now, 'number' => $number, 'content' => $scheduled['content']]); if (!$db->insertIntoTable('sendeds', ['at' => $now, 'target' => $number, 'content' => $scheduled['content']]))
{
echo 'Impossible d\'inserer le sms pour le numero ' . $number . "\n";
}
$id_sended = $db->lastId(); $id_sended = $db->lastId();
//Commande qui envoie le SMS //Commande qui envoie le SMS

View File

@ -102,7 +102,7 @@
* @param string $_POST['groups'] : Un tableau avec les ids des groupes auxquels envoyer le sms * @param string $_POST['groups'] : Un tableau avec les ids des groupes auxquels envoyer le sms
* @return boolean; * @return boolean;
*/ */
public function create($csrf = '', $api = false) public function create($csrf = '', $api = false, $discussion = false)
{ {
if (!$api) if (!$api)
{ {
@ -145,7 +145,7 @@
return false; return false;
} }
if (!internalTools::validateDate($date, 'Y-m-d H:i')) if (!internalTools::validateDate($date, 'Y-m-d H:i:s'))
{ {
if (!$api) if (!$api)
{ {
@ -167,6 +167,13 @@
} }
$id_scheduled = $db->lastId(); $id_scheduled = $db->lastId();
if ($discussion)
{
$_SESSION['discussion_wait_progress'] = isset($_SESSION['discussion_wait_progress']) ? $_SESSION['discussion_wait_progress'] : [];
$_SESSION['discussion_wait_progress'][] = $id_scheduled;
}
$db->insertIntoTable('events', ['type' => 'SCHEDULED_ADD', 'text' => 'Ajout d\'un SMS pour le ' . $date]); $db->insertIntoTable('events', ['type' => 'SCHEDULED_ADD', 'text' => 'Ajout d\'un SMS pour le ' . $date]);
$errors = false; $errors = false;

View File

@ -120,7 +120,7 @@
$_POST['groups'] = $groups; $_POST['groups'] = $groups;
$scheduleds = new scheduleds(); $scheduleds = new scheduleds();
$success = $scheduleds->create(true); $success = $scheduleds->create('', true);
if (!$success) if (!$success)
{ {

View File

@ -88,3 +88,103 @@ footer
color: #fff; color: #fff;
background-color: #000; background-color: #000;
} }
.goto:hover
{
cursor: pointer;
}
/** DISCUSSION **/
.table-discussions tbody tr:hover
{
cursor: pointer;
background-color: #999;
}
.discussion-container
{
overflow: auto;
}
.discussion-message
{
border-radius: 5px;
display: inline-block;
max-width: 90%;
padding: 10px;
position: relative;
}
.discussion-message-text
{
font-size: 1.3em;
}
.discussion-message-date
{
font-size: 0.9em;
}
.message-container
{
margin-bottom: 10px;
}
.message-received
{
background-color: #1abc9c;
float: left;
color: #fff;
}
.message-sended
{
background-color: #ddd;
float: right;
}
.message-received .discussion-message-date
{
color: #f0f0f0;
}
.message-sended .discussion-message-date
{
text-align: right;
color: #888;
}
.message-input
{
width: 100%;
max-width: 100%;
background-color: #ddd;
}
.message-input textarea
{
width: 100%;
resize: none;
height: 6em;
}
.message-input button
{
float: right;
margin-top: 8px;
}
.message-in-progress-hover
{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 900;
opacity: 0.7;
background-color: #fff;
font-size: 20px;
text-align: center;
padding-top: 10px;
}

View File

@ -33,8 +33,63 @@ function verifReceived()
}); });
} }
/**
* Cette fonction permet de scroller au dernier message
*/
function scrollDownDiscussion()
{
jQuery('.discussion-container').animate({scrollTop: 1000000});
}
jQuery(document).ready(function() jQuery(document).ready(function()
{ {
var verifReceivedInterval = setInterval(verifReceived, 10000); var verifReceivedInterval = setInterval(verifReceived, 10000);
jQuery('body').on('click', '.goto', function (e) {
e.preventDefault();
if (jQuery(this).attr('url'))
{
if (jQuery(this).attr('target'))
{
window.open(jQuery(this).attr('url'), jQuery(this).attr('target'));
}
else
{
window.location = jQuery(this).attr('url');
}
}
});
jQuery('body').on('submit', '.send-message-discussion', function (e)
{
e.preventDefault();
var form = jQuery(this);
var message = form.find('textarea').val();
var formData = new FormData(form[0]);
jQuery('.discussion-container').find('#send-message-spiner').remove();
jQuery('.discussion-container').append('<div class="text-center" id="send-message-spiner"><i class="fa fa-spinner fa-spin"></i></div>');
scrollDownDiscussion();
jQuery.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: formData,
contentType: false,
processData: false,
dataType: "json",
success: function (data)
{
if (!data.success)
{
showMessage(data.message.replace(/</g, "&lt;").replace(/>/g, "&gt;"), 0);
jQuery('.discussion-container').find('#send-message-spiner').remove();
}
}
}).done(function()
{
form.trigger("reset");
});
});
scrollDownDiscussion();
}); });

View File

@ -115,6 +115,46 @@
return $this->runQuery($query, $params); return $this->runQuery($query, $params);
} }
/**
* Récupère les SMS reçus depuis une date pour un numero
* @param $date : La date depuis laquelle on veux les SMS (au format 2014-10-25 20:10:05)
* @param $number : Le numéro
* @return array : Tableau avec tous les SMS depuis la date
*/
public function getReceivedsSinceForNumberOrderByDate($date, $number)
{
$query = "
SELECT *
FROM receiveds
WHERE at > STR_TO_DATE(:date, '%Y-%m-%d %h:%i:%s')
AND send_by = :number
ORDER BY at ASC
";
$params = array(
'date' => $date,
'number' => $number
);
return $this->runQuery($query, $params);
}
/**
* Récupère les SMS reçus groupé par numéro et trié par date
* @return array : Le tablea avec les sms et la date
*/
public function getDiscussions()
{
$query = "
SELECT MAX(at) as at, number
FROM (SELECT at, target as number FROM sendeds UNION (SELECT at, send_by as number FROM receiveds)) as discussions
GROUP BY number
ORDER BY at
";
return $this->runQuery($query);
}
/********************************/ /********************************/
/* PARTIE DES REQUETES CONTACTS */ /* PARTIE DES REQUETES CONTACTS */
/********************************/ /********************************/
@ -382,6 +422,57 @@
return $this->runQuery($query, $params, self::ROWCOUNT); return $this->runQuery($query, $params, self::ROWCOUNT);
} }
/**
* Cette fonction retourne les sms programmés pour un numéro donné et avant une date
* @param string $date : La date avant laquel on veux les numéros (format yyyy-mm-dd hh:mm:ss)
* @param string $number : Le numéro cible
* @return array : Les scheduleds correspondants
*/
public function getScheduledsBeforeDateForNumber($date, $number)
{
$query = "
SELECT *
FROM scheduleds
WHERE at <= :date
AND (
id IN (
SELECT id_scheduled
FROM scheduleds_numbers
WHERE number = :number
)
OR id IN (
SELECT id_scheduled
FROM scheduleds_contacts
WHERE id_contact IN (
SELECT id
FROM contacts
WHERE number = :number
)
)
OR id IN (
SELECT id_scheduled
FROM scheduleds_groups
WHERE id_group IN (
SELECT id_group
FROM groups_contacts
WHERE id_contact IN (
SELECT id
FROM contacts
WHERE number = :number
)
)
)
)
";
$params = array(
'date' => $date,
'number' => $number,
);
return $this->runQuery($query, $params);
}
/********************************/ /********************************/
/* PARTIE DES REQUETES COMMANDS */ /* PARTIE DES REQUETES COMMANDS */
/********************************/ /********************************/

View File

@ -0,0 +1,68 @@
<?php
//Template dashboard
$incs = new internalIncs();
$incs->head('Discussions - Show All');
?>
<div id="wrapper">
<?php
$incs->nav('discussions');
?>
<div id="page-wrapper">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Dashboard <small>Discussions</small>
</h1>
<ol class="breadcrumb">
<li>
<i class="fa fa-dashboard"></i> <a href="<?php echo $this->generateUrl('dashboard'); ?>">Dashboard</a>
</li>
<li class="active">
<i class="fa fa-comments-o"></i> Discussions
</li>
</ol>
</div>
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><i class="fa fa-comments-o fa-fw"></i> Liste des discussions</h3>
</div>
<div class="panel-body">
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped" id="table-discussions">
<thead>
<tr>
<th>Date du dernier message</th>
<th>Numéro</th>
</tr>
</thead>
<tbody>
<?php
foreach ($discussions as $discussion)
{
?>
<tr class="goto" url="<?php secho($this->generateUrl('discussions', 'show', [$discussion['number']])); ?>">
<td><?php secho($discussion['at']); ?></td>
<td><?php secho(isset($discussion['contact']) ? $discussion['contact'] . ' (' . $discussion['number'] . ')' : $discussion['number']); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php
$incs->footer();

134
templates/discussions/show.php Executable file
View File

@ -0,0 +1,134 @@
<?php
//Template dashboard
$incs = new internalIncs();
$incs->head('Discussions - Show All');
?>
<div id="wrapper">
<?php
$incs->nav('discussions');
?>
<div id="page-wrapper">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Discussion <small><?php secho($contact ? $contact . ' (' . $number . ')' : $number); ?></small>
</h1>
<ol class="breadcrumb">
<li>
<i class="fa fa-dashboard"></i> <a href="<?php echo $this->generateUrl('dashboard'); ?>">Dashboard</a>
</li>
<li>
<i class="fa fa-comments-o"></i> <a href="<?php echo $this->generateUrl('discussions'); ?>">Discussions</a>
</li>
<li class="active">
<?php secho($number); ?>
</li>
</ol>
</div>
</div>
<!-- /.row -->
<div class="row">
<div class="col-lg-12 discussion-container">
<div class="text-center"><i class="fa fa-spinner fa-spin"></i></div>
</div>
<div class="col-lg-12 message-input-container">
<div class="discussion-message message-input">
<form class="send-message-discussion" action="<?php secho($this->generateUrl('discussions', 'send', [$_SESSION['csrf']])); ?>" method="POST">
<textarea name="content" placeholder="Envoyer un message..."></textarea>
<input type="hidden" name="numbers[]" value="<?php secho($number); ?>" />
<button class="btn" ><span class="fa fa-fw fa-send-o"></span> Envoyer</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function () {
/**
* Cette fonction vérifie régulièrement les sms pour mettre à jour l'affichage
*/
function getmessages ()
{
ajaxTransactionId = Date.now();
jQuery.getJSON(HTTP_PWD + "/discussions/getmessages/<?php echo htmlspecialchars(urlencode($number)); ?>/" + ajaxTransactionId , function( data ) {
if (data.transactionId != ajaxTransactionId)
{
return false;
}
jQuery('.discussion-container').html('');
$.each(data.messages, function(key, message) {
switch (message.type)
{
case 'received' :
var texte = '' +
'<div class="clearfix message-container">' +
'<div class="discussion-message message-received">' +
'<div class="discussion-message-text">' + message.text.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</div>' +
'<div class="discussion-message-date">' + message.date.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</div>' +
'</div>' +
'</div>';
break;
case 'sended' :
var texte = '' +
'<div class="clearfix message-container">' +
'<div class="discussion-message message-sended">' +
'<div class="discussion-message-text">' + message.text.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</div>' +
'<div class="discussion-message-date">' + message.date.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</div>' +
'</div>' +
'</div>';
break;
case 'inprogress' :
var texte = '' +
'<div class="clearfix message-container">' +
'<div class="discussion-message message-sended">' +
'<div class="message-in-progress-hover"><i class="fa fa-spinner fa-spin"></i></div>' +
'<div class="discussion-message-text">' + message.text.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</div>' +
'<div class="discussion-message-date">' + message.date.replace(/</g, "&lt;").replace(/>/g, "&gt;") + '</div>' +
'</div>' +
'</div>';
break;
default :
var texte = '';
break;
}
jQuery('.discussion-container').append(texte);
});
scrollDownDiscussion();
});
}
/**
* Cette fonction permet de fixer la taille de la fenetre de discussion
*/
function fullHeightDiscussion()
{
var containerPosition = jQuery('.discussion-container').position();
var windowHeight = jQuery(window).height();
var messageInputContainer = jQuery('.message-input-container').outerHeight();
var footerHeight = jQuery('footer').outerHeight();
var containerHeight = Math.floor(windowHeight - (containerPosition.top + footerHeight * 2 + messageInputContainer));
jQuery('.discussion-container').outerHeight(containerHeight);
}
fullHeightDiscussion();
jQuery(window).on('resize', function () {
fullHeightDiscussion();
});
var getmessagesInterval = setInterval(getmessages, 2500);
});
</script>
<?php
$incs->footer();

View File

@ -34,6 +34,9 @@
<li <?php echo $page == 'scheduleds' ? 'class="active"' : ''; ?>> <li <?php echo $page == 'scheduleds' ? 'class="active"' : ''; ?>>
<a href="<?php echo $this->generateUrl('scheduleds'); ?>"><i class="fa fa-fw fa-envelope"></i> SMS</a> <a href="<?php echo $this->generateUrl('scheduleds'); ?>"><i class="fa fa-fw fa-envelope"></i> SMS</a>
</li> </li>
<li <?php echo $page == 'discussions' ? 'class="active"' : ''; ?>>
<a href="<?php echo $this->generateUrl('discussions'); ?>"><i class="fa fa-fw fa-comments"></i> Discussions</a>
</li>
<li <?php echo $page == 'commands' ? 'class="active"' : ''; ?>> <li <?php echo $page == 'commands' ? 'class="active"' : ''; ?>>
<a href="<?php echo $this->generateUrl('commands'); ?>"><i class="fa fa-fw fa-terminal"></i> Commandes</a> <a href="<?php echo $this->generateUrl('commands'); ?>"><i class="fa fa-fw fa-terminal"></i> Commandes</a>
</li> </li>

View File

@ -73,7 +73,7 @@
{ {
jQuery('.form-datetime').datetimepicker( jQuery('.form-datetime').datetimepicker(
{ {
format: 'yyyy-mm-dd hh:ii', format: 'yyyy-mm-dd hh:ii:ss',
autoclose: true, autoclose: true,
minuteStep: 1, minuteStep: 1,
language: 'fr' language: 'fr'

View File

@ -102,7 +102,7 @@
{ {
jQuery('.form-datetime').datetimepicker( jQuery('.form-datetime').datetimepicker(
{ {
format: 'yyyy-mm-dd hh:ii', format: 'yyyy-mm-dd hh:ii:ss',
autoclose: true, autoclose: true,
minuteStep: 1, minuteStep: 1,
language: 'fr' language: 'fr'