start add support for phone status + improve edit of phone for hidden phones

This commit is contained in:
osaajani 2023-02-18 16:39:07 +01:00
parent f9e64aee65
commit 38d350dfc2
19 changed files with 357 additions and 6 deletions

View File

@ -79,6 +79,11 @@ interface AdapterInterface
*/ */
public static function meta_support_read(): bool; public static function meta_support_read(): bool;
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool;
/** /**
* Does the implemented service support reception callback. * Does the implemented service support reception callback.
*/ */
@ -152,6 +157,15 @@ interface AdapterInterface
*/ */
public function test(): bool; public function test(): bool;
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string;
/** /**
* Method called on reception of a status update notification for a SMS. * Method called on reception of a status update notification for a SMS.
* *

View File

@ -111,6 +111,14 @@ namespace adapters;
return false; return false;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -226,6 +234,16 @@ namespace adapters;
return []; return [];
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public static function status_change_callback() public static function status_change_callback()
{ {
return null; return null;

View File

@ -121,6 +121,14 @@ namespace adapters;
return true; return true;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -301,6 +309,16 @@ namespace adapters;
return $response; return $response;
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
//Always return true as we cannot test because we would be needing a root account //Always return true as we cannot test because we would be needing a root account

View File

@ -209,6 +209,14 @@ class KannelAdapter implements AdapterInterface
return false; return false;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -354,6 +362,16 @@ class KannelAdapter implements AdapterInterface
return []; return [];
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
try try

View File

@ -174,6 +174,14 @@ class OctopushShortcodeAdapter implements AdapterInterface
return false; return false;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -325,6 +333,16 @@ class OctopushShortcodeAdapter implements AdapterInterface
return []; return [];
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
try try

View File

@ -173,6 +173,14 @@ class OctopushVirtualNumberAdapter implements AdapterInterface
return false; return false;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -317,6 +325,16 @@ class OctopushVirtualNumberAdapter implements AdapterInterface
return []; return [];
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
try try

View File

@ -162,6 +162,14 @@ namespace adapters;
return true; return true;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -327,6 +335,16 @@ namespace adapters;
} }
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
try try

View File

@ -166,6 +166,14 @@ namespace adapters;
return true; return true;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -317,6 +325,16 @@ namespace adapters;
} }
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
try try

View File

@ -116,6 +116,14 @@ namespace adapters;
return true; return true;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -287,6 +295,16 @@ namespace adapters;
} }
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
return true; return true;

View File

@ -160,6 +160,14 @@ class TwilioVirtualNumberAdapter implements AdapterInterface
return true; return true;
} }
/**
* Does the implemented service support updating phone status.
*/
public static function meta_support_phone_status(): bool
{
return false;
}
/** /**
* Does the implemented service support flash smss. * Does the implemented service support flash smss.
*/ */
@ -295,6 +303,16 @@ class TwilioVirtualNumberAdapter implements AdapterInterface
} }
} }
/**
* Method called to verify phone status
*
* @return string : Return one phone status among 'available', 'unavailable', 'no_credit'
*/
public function check_phone_status(): string
{
return \models\Phone::STATUS_AVAILABLE;
}
public function test(): bool public function test(): bool
{ {
try try

View File

@ -236,6 +236,19 @@ namespace controllers\internals;
return true; return true;
} }
/**
* Update a phone status.
*
* @param int $id : Phone id
* @param string $status : The new status of the phone
*
* @return bool : false on error, true on success
*/
public function update_status(int $id, string $status) : bool
{
return (bool) $this->get_model()->update($id, ['status' => $status]);
}
/** /**
* Get the model for the Controller. * Get the model for the Controller.
*/ */

View File

@ -710,7 +710,7 @@ namespace controllers\publics;
$priority = $_POST['priority'] ?? $phone['priority']; $priority = $_POST['priority'] ?? $phone['priority'];
$priority = max(((int) $priority), 0); $priority = max(((int) $priority), 0);
$adapter = $_POST['adapter'] ?? $phone['adapter']; $adapter = $_POST['adapter'] ?? $phone['adapter'];
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data']); $adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data'], true);
$adapter_data = is_array($adapter_data) ? $adapter_data : [$adapter_data]; $adapter_data = is_array($adapter_data) ? $adapter_data : [$adapter_data];
$limits = $_POST['limits'] ?? $limits; $limits = $_POST['limits'] ?? $limits;
$limits = is_array($limits) ? $limits : [$limits]; $limits = is_array($limits) ? $limits : [$limits];
@ -890,4 +890,44 @@ namespace controllers\publics;
return $this->json($return); return $this->json($return);
} }
/**
* Trigger re-checking of a phone status
*
* @param int $id : Id of phone to re-check status
*/
public function post_update_phone_status ($id)
{
$return = self::DEFAULT_RETURN;
$phone = $this->internal_phone->get_for_user($this->user['id'], $id);
if (!$phone)
{
$return['error'] = self::ERROR_CODES['CANNOT_UPDATE'];
$return['message'] = self::ERROR_MESSAGES['CANNOT_UPDATE'];
$this->auto_http_code(false);
return $this->json($return);
}
//Check adapter is working correctly with thoses names and data
$adapter_classname = $phone['adapter'];
if (!call_user_func([$adapter_classname, 'meta_support_phone_status']))
{
$return['error'] = self::ERROR_CODES['CANNOT_UPDATE'];
$return['message'] = self::ERROR_MESSAGES['CANNOT_UPDATE'];
$this->auto_http_code(false);
return $this->json($return);
}
$adapter_instance = new $adapter_classname($phone['adapter_data']);
$new_status = $adapter_instance->check_phone_status();
$status_update = $this->internal_phone->update_status($id, $new_status);
$return['response'] = $new_status;
$this->auto_http_code(true);
return $this->json($return);
}
} }

View File

@ -88,6 +88,11 @@ class Phone extends \descartes\Controller
{ {
$phone['callback_end_call'] = \descartes\Router::url('Callback', 'end_call', ['id_phone' => $phone['id']], ['api_key' => $api_key]); $phone['callback_end_call'] = \descartes\Router::url('Callback', 'end_call', ['id_phone' => $phone['id']], ['api_key' => $api_key]);
} }
if ($adapter['meta_support_phone_status'])
{
$phone['support_phone_status'] = true;
}
} }
header('Content-Type: application/json'); header('Content-Type: application/json');
@ -425,7 +430,14 @@ class Phone extends \descartes\Controller
continue; continue;
} }
if ($find_adapter['meta_hidden']) $current_phone = $this->internal_phone->get_for_user($id_user, $id_phone);
if (!$current_phone)
{
continue;
}
// We can only use an hidden adapter if it was already the adapter we was using
if ($find_adapter['meta_hidden'] && $adapter != $current_phone['adapter'])
{ {
continue; continue;
} }
@ -499,4 +511,44 @@ class Phone extends \descartes\Controller
return $this->redirect(\descartes\Router::url('Phone', 'list')); return $this->redirect(\descartes\Router::url('Phone', 'list'));
} }
/**
* Re-check phone status
* @param array int $_GET['ids'] : ids of phones we want to update status
* @param $csrf : CSRF token
*/
public function update_status ($csrf)
{
if (!$this->verify_csrf($csrf))
{
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
return $this->redirect(\descartes\Router::url('Phone', 'add'));
}
$ids = $_GET['ids'] ?? [];
$id_user = $_SESSION['user']['id'];
foreach ($ids as $id)
{
$phone = $this->internal_phone->get_for_user($id_user, $id);
//Check adapter is working correctly with thoses names and data
$adapter_classname = $phone['adapter'];
if (!call_user_func([$adapter_classname, 'meta_support_phone_status']))
{
continue;
}
$adapter_instance = new $adapter_classname($phone['adapter_data']);
$new_status = $adapter_instance->check_phone_status();
$status_update = $this->internal_phone->update_status($id, $new_status);
}
\FlashMessage\FlashMessage::push('success', 'Les status des téléphones ont bien été mis à jour.');
return $this->redirect(\descartes\Router::url('Phone', 'list'));
}
} }

View File

@ -0,0 +1,38 @@
<?php
use Phinx\Migration\AbstractMigration;
class AddStatusPhone extends AbstractMigration
{
/**
* Change Method.
*
* Write your reversible migrations using this method.
*
* More information on writing migrations is available here:
* https://book.cakephp.org/phinx/0/en/migrations.html
*
* The following commands can be used in this method and Phinx will
* automatically reverse them when rolling back:
*
* createTable
* renameTable
* addColumn
* addCustomColumn
* renameColumn
* addIndex
* addForeignKey
*
* Any other destructive changes will result in an error when trying to
* rollback the migration.
*
* Remember to call "create()" or "update()" and NOT "save()" when working
* with the Table class.
*/
public function change()
{
$table = $this->table('phone');
$table->addColumn('status', 'enum', ['values' => ['available', 'unavailable', 'no_credit'], 'default' => 'available']);
$table->update();
}
}

View File

@ -14,6 +14,10 @@ namespace models;
class Phone extends StandardModel class Phone extends StandardModel
{ {
const STATUS_AVAILABLE = 'available';
const STATUS_UNAVAILABLE = 'unavailable';
const STATUS_NO_CREDIT = 'no_credit';
/** /**
* Return all phones that belongs to active users * Return all phones that belongs to active users
* *

View File

@ -164,6 +164,7 @@
'delete' => '/phone/delete/{csrf}/', 'delete' => '/phone/delete/{csrf}/',
'edit' => '/phone/edit/', 'edit' => '/phone/edit/',
'update' => '/phone/update/{csrf}/', 'update' => '/phone/update/{csrf}/',
'update_status' => '/phone/update_status/{csrf}/'
], ],
'Call' => [ 'Call' => [
@ -206,6 +207,9 @@
'post_update_phone' => [ 'post_update_phone' => [
'/api/phone/{id}/', '/api/phone/{id}/',
], ],
'post_update_phone_status' => [
'/api/phone/{id}/status/',
],
'delete_phone' => [ 'delete_phone' => [
'/api/phone/{id}/', '/api/phone/{id}/',
], ],

View File

@ -111,7 +111,7 @@ jQuery(document).ready(function ()
{ {
data: '_', data: '_',
render: function (data, type, row, meta) { render: function (data, type, row, meta) {
return '<a class="btn btn-info preview-button" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>'; return '<a class="btn btn-info preview-button inline" href="#" data-id-group="' + jQuery.fn.dataTable.render.text().display(row.id) + '"><span class="fa fa-eye"></span></a>';
}, },
}, },
{ {

View File

@ -65,13 +65,15 @@
</p> </p>
<select name="phones[<?php $this->s($phone['id']); ?>][adapter]" class="form-control adapter-select"> <select name="phones[<?php $this->s($phone['id']); ?>][adapter]" class="form-control adapter-select">
<?php foreach ($adapters as $adapter) { ?> <?php foreach ($adapters as $adapter) { ?>
<?php if ($adapter['meta_hidden'] === false) { ?> <?php if ($adapter['meta_hidden'] === false || $phone['adapter'] == $adapter['meta_classname']) { ?>
<option <option
value="<?= $adapter['meta_classname'] ?>" value="<?= $adapter['meta_classname'] ?>"
data-description="<?php $this->s($adapter['meta_description']); ?>" data-description="<?php $this->s($adapter['meta_description']); ?>"
data-data-fields="<?php $this->s(json_encode($adapter['meta_data_fields'])); ?>" data-data-fields="<?php $this->s(json_encode($adapter['meta_data_fields'])); ?>"
<?php if ($phone['adapter'] == $adapter['meta_classname']) { ?> <?php if ($phone['adapter'] == $adapter['meta_classname']) { ?>
data-phone-adapter-data="<?php $this->s($phone['adapter_data']); ?>" <?php if (!$adapter['meta_hide_data']) { ?>
data-phone-adapter-data="<?php $this->s($phone['adapter_data']); ?>"
<?php } ?>
selected selected
<?php } ?> <?php } ?>
> >

View File

@ -58,6 +58,7 @@
</div> </div>
<div class="text-right col-xs-6 no-padding"> <div class="text-right col-xs-6 no-padding">
<strong>Action pour la séléction :</strong> <strong>Action pour la séléction :</strong>
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'update_status', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-refresh"></span> Rafraichir le status</button>
<button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'edit'); ?>"><span class="fa fa-edit"></span> Modifier</button> <button class="btn btn-default" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'edit'); ?>"><span class="fa fa-edit"></span> Modifier</button>
<button class="btn btn-default btn-confirm" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'delete', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-trash-o"></span> Supprimer</button> <button class="btn btn-default btn-confirm" type="submit" formaction="<?php echo \descartes\Router::url('Phone', 'delete', ['csrf' => $_SESSION['csrf']]); ?>"><span class="fa fa-trash-o"></span> Supprimer</button>
</div> </div>
@ -90,7 +91,28 @@ jQuery(document).ready(function ()
}, },
"columns" : [ "columns" : [
{data: 'id', render: jQuery.fn.dataTable.render.text()}, {data: 'id', render: jQuery.fn.dataTable.render.text()},
{data: 'name', render: jQuery.fn.dataTable.render.text()}, {
data: 'name',
render: function (data, type, row, meta) {
html = jQuery.fn.dataTable.render.text().display(data)
switch (row.status)
{
case 'available':
html += ' - <span class="text-success">Disponible</span>'
break;
case 'unavailable':
html += ' - <span class="text-danger">Indisponible</span>'
break;
case 'no_credit':
html += ' - <span class="text-warning">Plus de crédit</span>'
break;
}
return html
},
},
{data: 'priority', render: jQuery.fn.dataTable.render.text()}, {data: 'priority', render: jQuery.fn.dataTable.render.text()},
{data: 'adapter', render: jQuery.fn.dataTable.render.text()}, {data: 'adapter', render: jQuery.fn.dataTable.render.text()},
{ {