Compare commits

...

17 Commits

Author SHA1 Message Date
osaajani 064d6fd941 Fix url parsing 2024-02-26 12:07:19 +01:00
osaajani 6e6c51a9ee Add support for automatic response to SMS stop 2024-02-25 11:11:25 +01:00
osaajani 6321899e02 Update descartes framework to improve env.php constants handling 2024-02-25 11:04:45 +01:00
osaajani cf4dd2f075 Fix sms stop that whose ignored due to a bug 2023-11-20 15:42:09 +01:00
osaajani 5d1015e190 Fix static function on inbound callback and endcallback for adapters 2023-09-22 18:27:17 +02:00
osaajani 3b2dddbea3 up version 2023-09-19 18:35:13 +02:00
osaajani 490c6499e2 Fix sms settings check on api 2023-09-19 18:34:59 +02:00
osaajani 4e165ec32d Version 3.8.0 add support for http link shortening in sms 2023-09-17 16:27:13 +02:00
osaajani 241d079ffb Add link shortening for http links in sms, using YOURLS 2023-09-17 16:16:35 +02:00
osaajani fb3f9425d1 User setting update now create setting if it doesn't exists yet instead of returning an error 2023-09-17 16:12:31 +02:00
osaajani 9aa3eca812 Add verification on phone number on contact import 2023-07-18 17:16:34 +02:00
osaajani 347084b5c4 improve perfs on status update by sizing down uid and adding an index 2023-06-06 20:32:04 +02:00
osaajani aaeb7b64e9 Add index on sms timestamps for perfs 2023-06-06 18:39:48 +02:00
Your Name 7c94c24192 update composer 2023-06-06 12:52:20 +02:00
osaajani 03f7c463a2 jquery v3 incompatible with magicsuggest 2023-06-06 12:22:40 +02:00
osaajani e95677aec5 . 2023-05-31 18:43:18 +02:00
osaajani c90da4bd5d Fix type detection in router invocation descartes for php >= 8 2023-05-31 18:34:46 +02:00
39 changed files with 433 additions and 114 deletions

View File

@ -1 +1 @@
v3.7.0
v3.9.1

View File

@ -207,7 +207,7 @@ interface AdapterInterface
* ]
* ]
*/
public function inbound_call_callback(): array;
public static function inbound_call_callback(): array;
/**
* Method called on reception of a end call notification.
@ -221,5 +221,5 @@ interface AdapterInterface
* ]
* ]
*/
public function end_call_callback(): array;
public static function end_call_callback(): array;
}

View File

@ -259,12 +259,12 @@ namespace adapters;
return true;
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -336,12 +336,12 @@ namespace adapters;
return [];
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -508,12 +508,12 @@ class KannelAdapter implements AdapterInterface
return $response;
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -486,12 +486,12 @@ class OctopushShortcodeAdapter implements AdapterInterface
return $response;
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -479,12 +479,12 @@ class OctopushVirtualNumberAdapter implements AdapterInterface
return $response;
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -499,12 +499,12 @@ class OdysseyMessagingAdapter implements AdapterInterface
return $response;
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -406,12 +406,12 @@ namespace adapters;
return [];
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -396,12 +396,12 @@ namespace adapters;
return [];
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

View File

@ -351,7 +351,7 @@ namespace adapters;
return [];
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
$response = [
'error' => false,
@ -380,7 +380,7 @@ namespace adapters;
return $response;
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
$response = [
'error' => false,

View File

@ -374,12 +374,12 @@ class TwilioVirtualNumberAdapter implements AdapterInterface
return [];
}
public function inbound_call_callback(): array
public static function inbound_call_callback(): array
{
return [];
}
public function end_call_callback(): array
public static function end_call_callback(): array
{
return [];
}

6
assets/js/jquery.js vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -141,8 +141,11 @@ namespace controllers\internals;
$nb_insert = 0;
$head = null;
$line_nb = 0;
while ($line = fgetcsv($file_handler))
{
$line_nb ++;
if (null === $head)
{
$head = $line;
@ -185,9 +188,16 @@ namespace controllers\internals;
}
$data = json_encode($data);
$contact_name = $line[array_keys($line)[0]];
$phone_number = \controllers\internals\Tool::parse_phone($line[array_keys($line)[1]]);
if (!$phone_number)
{
throw new \Exception('Erreur à la ligne ' . $line_nb . ' colonne 1, numéro de téléphone invalide.');
}
try
{
$success = $this->create($id_user, $line[array_keys($line)[1]], $line[array_keys($line)[0]], $data);
$success = $this->create($id_user, $line[array_keys($line)[1]], $contact_name, $data);
if ($success)
{
++$nb_insert;

View File

@ -0,0 +1,62 @@
<?php
/*
* This file is part of RaspiSMS.
*
* (c) Pierre-Lin Bonnemaison <plebwebsas@gmail.com>
*
* This source file is subject to the GPL-3.0 license that is bundled
* with this source code in the file LICENSE.
*/
namespace controllers\internals;
use Exception;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
/**
* Mailing class.
*/
class LinkShortener
{
/**
* Shorten an URL using the configured YOURLS instance
*/
public static function shorten($url)
{
$api_url = URL_SHORTENER['HOST'] . '/yourls-api.php';
$data = [
'action' => 'shorturl',
'format' => 'json',
'username' => URL_SHORTENER['USER'],
'password' => URL_SHORTENER['PASS'],
'url' => $url,
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $api_url);
curl_setopt($ch, CURLOPT_HEADER, 0); // No header in the result
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // Enable follow location
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return, do not echo result
curl_setopt($ch, CURLOPT_POST, 1); // This is a POST request
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);
try
{
$response = json_decode($response, true, 512, JSON_THROW_ON_ERROR);
}
catch (\Exception $e)
{
return false;
}
$shortlink = $response['shorturl'] ?? false;
return $shortlink;
}
}

0
controllers/internals/Mailer.php Executable file → Normal file
View File

View File

@ -11,6 +11,8 @@
namespace controllers\internals;
use Exception;
class Received extends StandardController
{
protected $model;
@ -88,14 +90,6 @@ namespace controllers\internals;
return false;
}
//Check if the received message is a SMS STOP and we must register it
$internal_smsstop = new SmsStop($this->bdd);
$is_stop = $internal_smsstop->check_for_stop($received['text']);
if ($is_stop)
{
$internal_smsstop->create($id_user, $origin);
}
//Link medias
$internal_media = new Media($this->bdd);
foreach ($media_ids as $media_id)
@ -116,6 +110,32 @@ namespace controllers\internals;
return false;
}
//Check if the received message is a SMS STOP and we must register it
$internal_smsstop = new SmsStop($this->bdd);
$is_stop = $internal_smsstop->check_for_stop($received['text']);
if ($is_stop)
{
$stop_exists = (bool) $internal_smsstop->get_by_number_for_user($id_user, $origin);
if ($stop_exists)
{
return $id_received;
}
$internal_smsstop->create($id_user, $origin);
//If stop response enabled, respond to user
//(this will happen only for first stop, any further stop will not trigger responses)
$internal_setting = new Setting($this->bdd);
$user_settings = $internal_setting->gets_for_user($id_user);
if ((int) ($user_settings['smsstop_respond'] ?? false))
{
$response = $user_settings['smsstop_response'];
$internal_scheduled = new Scheduled($this->bdd);
$internal_scheduled->create($id_user, (new \DateTime())->format('Y-m-d H:i:s'), $response, $id_phone, null, false, false, \models\SmsStop::SMS_STOP_TAG, [['number' => $origin, 'data' => '[]']]);
}
}
return $id_received;
}

View File

@ -450,7 +450,8 @@ use Monolog\Logger;
$users_smsstops = [];
$users_settings = [];
$users_phones = [];
$users_phone_groups = [];
$users_phone_groups = [];
$shortlink_cache = [];
$now = new \DateTime();
$now = $now->format('Y-m-d H:i:s');
@ -601,9 +602,10 @@ use Monolog\Logger;
continue;
}
//Remove messages to smsstops numbers
if (($users_smsstops[$id_user] ?? false) && in_array($target['number'], $users_smsstops[$id_user]))
//Remove messages to smsstops numbers if not with tag SMS_STOP
if ($scheduled['tag'] != \models\SmsStop::SMS_STOP_TAG && ($users_smsstops[$id_user] ?? false) && in_array($target['number'], $users_smsstops[$id_user]))
{
unset($targets[$key]);
continue;
}
@ -643,6 +645,33 @@ use Monolog\Logger;
$text = Tool::convert_to_gsm0338($text);
}
// If the text contain http links we must replace them
if (ENABLE_URL_SHORTENER && ((int) ($users_settings[$id_user]['shorten_url'] ?? false)))
{
$http_links = Tool::search_http_links($text);
if ($http_links !== false)
{
foreach ($http_links as $http_link)
{
if (!array_key_exists($http_link, $shortlink_cache))
{
$shortlkink = LinkShortener::shorten($http_link);
// If link shortening failed, keep original one
if ($shortlkink === false)
{
continue;
}
$shortlink_cache[$http_link] = $shortlkink;
}
$shortlink = $shortlink_cache[$http_link];
$text = str_replace($http_link, $shortlink, $text);
}
}
}
/*
Choose phone if no phone defined for message
Phones are choosen using type, priority and remaining volume :

View File

@ -35,6 +35,18 @@ namespace controllers\internals;
return $settings_array;
}
/**
* Get a user setting by his name for a user.
*
* @param int $id_user : user id
*
* @return array
*/
public function get_by_name_for_user(int $id_user, string $name)
{
return $this->get_model()->get_by_name_for_user($id_user, $name);
}
/**
* Update a setting by his name and user id.
*

View File

@ -73,7 +73,8 @@ namespace controllers\internals;
*/
public function check_for_stop(string $str)
{
return 'stop' == trim(mb_strtolower($str));
$str = trim(mb_strtolower($str));
return 'stop' == $str || 'stop sms' == $str;
}
/**

View File

@ -85,6 +85,22 @@ use BenMorel\GsmCharsetConverter\Converter;
return '<a href="' . self::s($url, false, true, false) . '">' . self::s($number_format, false, true, false) . '</a>';
}
/**
* Check for http link in a text
*
* @param string $text : Text to search a link in
*
* @return bool|array : False if no link in the text, or an array of all http links
*/
public static function search_http_links($text)
{
$regex = "#http(s?)://\S+#i";
$matches = [];
$nb_matches = preg_match_all($regex, $text, $matches);
return $nb_matches > 0 ? $matches[0] : false;
}
/**
* Cette fonction fait la correspondance entre un type d'evenement et une icone font awesome.
*

View File

@ -426,7 +426,7 @@ namespace controllers\publics;
$at = (string) $at;
$text = (string) $text;
if (($this->user['settings']['mms'] ?? false) && $mms)
if ($mms && !(int)($this->user['settings']['mms'] ?? false))
{
$return = self::DEFAULT_RETURN;
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];

View File

@ -11,6 +11,8 @@
namespace controllers\publics;
use Exception;
/**
* Page des contacts.
*/
@ -345,40 +347,28 @@ namespace controllers\publics;
return $this->redirect(\descartes\Router::url('Contact', 'list'));
}
//Try to import file
$invalid_type = false;
switch ($read_file['mime_type'])
try
{
case 'text/csv':
$result = $this->internal_contact->import_csv($id_user, $read_file['content']);
break;
case 'application/json':
$result = $this->internal_contact->import_json($id_user, $read_file['content']);
break;
default:
if ('csv' === $read_file['extension'])
{
$result = false;
switch (true)
{
case ($read_file['mime_type'] === 'text/csv' || 'csv' === $read_file['extension']) :
$result = $this->internal_contact->import_csv($id_user, $read_file['content']);
}
elseif ('json' === $read_file['extension'])
{
$result = $this->internal_contact->import_json($id_user, $read_file['content']);
}
else
{
$invalid_type = true;
$result = false;
}
}
if ($invalid_type)
break;
case ($read_file['mime_type'] === 'text/json' || 'json' === $read_file['extension']) :
$result = $this->internal_contact->import_json($id_user, $read_file['content']);
break;
default:
throw new Exception('Le type de fichier n\'est pas valide.');
}
}
catch (\Exception $e)
{
\FlashMessage\FlashMessage::push('danger', 'Le type de fichier n\'est pas valide.');
\FlashMessage\FlashMessage::push('danger', 'Erreur lors de l\'import: ' . $e->getMessage());
return $this->redirect(\descartes\Router::url('Contact', 'list'));
}

View File

@ -75,12 +75,27 @@ namespace controllers\publics;
$setting_value = json_encode($setting_value);
}
$update_setting_result = $this->internal_setting->update_for_user($_SESSION['user']['id'], $setting_name, $setting_value);
if (false === $update_setting_result)
// If setting dont exists yet, create it, else update
$setting = $this->internal_setting->get_by_name_for_user($_SESSION['user']['id'], $setting_name);
if (!$setting)
{
\FlashMessage\FlashMessage::push('danger', 'Impossible de mettre à jour ce réglage.');
$success = $this->internal_setting->create($_SESSION['user']['id'], $setting_name, $setting_value);
if (false === $success)
{
\FlashMessage\FlashMessage::push('danger', 'Impossible de mettre à jour ce réglage.');
return $this->redirect(\descartes\Router::url('Setting', 'show'));
return $this->redirect(\descartes\Router::url('Setting', 'show'));
}
}
else
{
$update_setting_result = $this->internal_setting->update_for_user($_SESSION['user']['id'], $setting_name, $setting_value);
if (false === $update_setting_result)
{
\FlashMessage\FlashMessage::push('danger', 'Impossible de mettre à jour ce réglage.');
return $this->redirect(\descartes\Router::url('Setting', 'show'));
}
}
$settings = $this->internal_setting->gets_for_user($_SESSION['user']['id']);

View File

@ -0,0 +1,24 @@
<?php
use Phinx\Migration\AbstractMigration;
class AddIndexToSmsTimestamps extends AbstractMigration
{
/**
* Add indexes on most SMS table timestamp (and possibly other fields) to improve perfs on query using date, like stats, sending limits, etc.
*/
public function change()
{
$table = $this->table('sended');
$table->addIndex('at');
$table->update();
$table = $this->table('received');
$table->addIndex('at');
$table->update();
$table = $this->table('scheduled');
$table->addIndex('at');
$table->update();
}
}

View File

@ -0,0 +1,24 @@
<?php
use Phinx\Migration\AbstractMigration;
class AddIndexOnSendedUid extends AbstractMigration
{
/**
* Modify sended uid and call to be 100 char long, we dont need a 500 char uid and too long a char ss hurting perfs
* Add index on sended uid to make status update more efficient
*/
public function change()
{
$table = $this->table('sended');
$table->changeColumn('uid', 'string', ['limit' => 100]);
$table->addIndex('uid');
$table->update();
$table = $this->table('call');
$table->changeColumn('uid', 'string', ['limit' => 100]);
$table->addIndex('uid');
$table->update();
}
}

View File

@ -91,21 +91,21 @@
/**
* Cette fonction permet de faire un retour sous forme de json
* @param array $data : Les données à retourner sous forme de json
* @param array $datas : Les données à retourner sous forme de json
* @param boolean $secure : Défini si l'affichage doit être sécurisé contre les XSS, par défaut true
* @return ApiController : On retourne l'API controlleur lui meme pour pouvoir chainer
*/
public function json ($data, $secure = true)
public function json ($datas, $secure = true)
{
header('Content-Type: application/json');
if ($secure)
{
echo htmlspecialchars(json_encode($data), ENT_NOQUOTES);
echo htmlspecialchars(json_encode($datas), ENT_NOQUOTES);
}
else
{
echo json_encode($data);
echo json_encode($datas);
}
return $this;

View File

@ -24,7 +24,7 @@
if (!is_readable($template_path))
{
throw new DescartesTemplateNotReadableException('Template ' . $template_path . ' is not readable.');
throw new exceptions\DescartesExceptionTemplateNotReadable('Template ' . $template_path . ' is not readable.');
}
require $template_path;

View File

@ -72,8 +72,7 @@
protected static function clean_url (string $url)
{
$to_remove = parse_url(HTTP_PWD, PHP_URL_PATH);
$url = mb_strcut($url, mb_strlen($to_remove));
$url = mb_strcut($url, $to_remove ? mb_strlen($to_remove) : 0);
$url = parse_url($url, PHP_URL_PATH);
return $url;
@ -252,6 +251,7 @@
$type = $parameter->getType();
$type = $type ?? false;
$type = ($type instanceof \ReflectionNamedType) ? $type->getName() : $type;
if ($type)
{

View File

@ -4,7 +4,7 @@
/*
* Define Descartes env
*/
$http_dir_path = '/raspisms'; //Path we need to put after servername in url to access app
$http_dir_path = ''; //Path we need to put after servername in url to access app
$https = $_SERVER['HTTPS'] ?? 0;
// Check for proxy forward
@ -27,10 +27,9 @@
$port = $proxy ? '' : $port;
$http_server_port = $port ? ':' . $port : '';
$pwd = substr(__DIR__, 0, strrpos(__DIR__, '/'));
$http_pwd = $http_protocol . $http_server_name . $http_server_port . $http_dir_path;
$env = [
//Global http and file path
@ -39,31 +38,25 @@
'HTTP_SERVER_NAME' => $http_server_name,
'HTTP_SERVER_PORT' => $http_server_port,
'PWD' => $pwd,
'HTTP_PWD' => $http_pwd,
//path of back resources
'PWD_CONTROLLER' => $pwd . '/controllers', //Controllers dir
'PWD_MODEL' => $pwd . '/models', //Models dir
'PWD_TEMPLATES' => $pwd . '/templates', //Templates dir
//path of front resources
'PWD_ASSETS' => $pwd . '/assets', //Assets dir
'HTTP_PWD_ASSETS' => $http_pwd . '/assets', //HTTP path of asset dir
'PWD_ASSETS' => $pwd . '/assets', //Assets dir
//images
'PWD_IMG' => $pwd . '/assets' . '/img',
'HTTP_PWD_IMG' => $http_pwd . '/assets' . '/img',
//css
'PWD_CSS' => $pwd . '/assets' . '/css',
'HTTP_PWD_CSS' => $http_pwd . '/assets' . '/css',
//javascript
'PWD_JS' => $pwd . '/assets' . '/js',
'HTTP_PWD_JS' => $http_pwd . '/assets' . '/js',
//fonts
'PWD_FONT' => $pwd . '/assets' . '/font',
'HTTP_PWD_FONT' => $http_pwd . '/assets' . '/font',
];

View File

@ -21,6 +21,7 @@
$environment = [];
$env = [];
// Load descartes base env
require_once(__DIR__ . '/env.php');
$environment = array_merge($environment, $env);
@ -31,11 +32,8 @@
$environment = array_merge($environment, $env);
}
//Define all Descartes constants
define_array($environment);
### GLOBAL ENV ###
$environment = [];
//Load global app env
$env = [];
if (file_exists(__DIR__ . '/../env.php'))
{
@ -43,19 +41,30 @@
$environment = array_merge($environment, $env);
}
define_array($environment);
### SPECIFIC ENV ###
$environment = [];
// Load specific environment env
$env = [];
if (defined('ENV') && file_exists(__DIR__ . '/../env.' . ENV . '.php'))
if (isset($environment['ENV']) && file_exists(__DIR__ . '/../env.' . $environment['ENV'] . '.php'))
{
require_once(__DIR__ . '/../env.' . ENV . '.php');
require_once(__DIR__ . '/../env.' . $environment['ENV'] . '.php');
$environment = array_merge($environment, $env);
}
### BUILD HTTP PWD CONSTS ###
// We compute http pwd at last minute to allow for simple overriding by user
// by simply defining custom HTTP_* (PROTOCOL, SERVER_NAME, SERVER_PORT, DIR_PATH)
$http_pwd = $environment['HTTP_PROTOCOL'] . $environment['HTTP_SERVER_NAME'] . $environment['HTTP_SERVER_PORT'] . $environment['HTTP_DIR_PATH'];
$env = [
"HTTP_PWD" => $http_pwd,
'HTTP_PWD_ASSETS' => $http_pwd . '/assets', //HTTP path of asset dir
'HTTP_PWD_IMG' => $http_pwd . '/assets' . '/img',
'HTTP_PWD_CSS' => $http_pwd . '/assets' . '/css',
'HTTP_PWD_JS' => $http_pwd . '/assets' . '/js',
'HTTP_PWD_FONT' => $http_pwd . '/assets' . '/font',
];
$environment = array_merge($environment, $env);
define_array($environment);
}

View File

@ -2,28 +2,31 @@
/*
This file define constants and options for the app
*/
$dir_path = '/raspisms';
$http_pwd = $environment['HTTP_PROTOCOL'] . $dir_path . $environment['HTTP_SERVER_PORT'] . $environment['HTTP_DIR_PATH'];
$env = [
'ENV' => '%APP_ENV%', #env name (probably 'dev' or 'prod'), this value is used to get the env.XXX.php.dist matching env file
'SESSION_NAME' => 'raspisms',
'HTTP_DIR_PATH' => $dir_path, // Override default dir path
//RaspiSMS settings
'WEBSITE_TITLE' => 'RaspiSMS',
'WEBSITE_DESCRIPTION' => '',
'WEBSITE_AUTHOR' => 'Raspberry Pi FR',
'PWD_SCRIPTS' => PWD . '/scripts',
'PWD_RECEIVEDS' => PWD . '/receiveds',
'HTTP_PWD_SOUND' => HTTP_PWD_ASSETS . '/sounds',
'PWD_ADAPTERS' => PWD . '/adapters',
'PWD_DATA' => PWD . '/data',
'HTTP_PWD_DATA' => HTTP_PWD . '/data',
'PWD_DATA_PUBLIC' => PWD . '/data/public',
'HTTP_PWD_DATA_PUBLIC' => HTTP_PWD . '/data/public',
'PWD_SCRIPTS' => $environment['PWD'] . '/scripts',
'PWD_RECEIVEDS' => $environment['PWD'] . '/receiveds',
'HTTP_PWD_SOUND' => $http_pwd . '/assets' . '/sounds',
'PWD_ADAPTERS' => $environment['PWD'] . '/adapters',
'PWD_DATA' => $environment['PWD'] . '/data',
'HTTP_PWD_DATA' => $http_pwd . '/data',
'PWD_DATA_PUBLIC' => $environment['PWD'] . '/data/public',
'HTTP_PWD_DATA_PUBLIC' => $http_pwd . '/data/public',
'PWD_LOGS' => '/var/log/raspisms',
'PWD_PID' => '/var/run/raspisms',
'APP_SECRET' => '%APP_SECRET%',
'ENABLE_COMMAND' => false,
'ENABLE_ACCOUNT_DELETION' => true,
'ENABLE_URL_SHORTENER' => %APP_URL_SHORTENER%,
//E-mail types
'EMAIL_RESET_PASSWORD' => [
@ -85,6 +88,9 @@
'force_gsm_alphabet' => 0,
'phone_limit' => 0,
'phone_priority' => 0,
'shorten_url' => 0,
'smsstop_respond' => 1,
'smsstop_response' => 'Demande prise en compte, vous ne recevrez plus de messages.',
],
];

View File

@ -21,4 +21,11 @@
'FROM' => '%APP_MAIL_FROM%',
],
//YOURLS url shortener settings
'URL_SHORTENER' => [
'HOST' => '%APP_URL_SHORTENER_HOST%',
'USER' => '%APP_URL_SHORTENER_USER%',
'PASS' => '%APP_URL_SHORTENER_PASS%',
]
];

View File

@ -27,6 +27,18 @@ namespace models;
return $this->_update($this->get_table_name(), ['value' => $value], ['id_user' => $id_user, 'name' => $name]);
}
/**
* Get a user setting by his name for a user.
*
* @param int $id_user : user id
*
* @return array
*/
public function get_by_name_for_user(int $id_user, string $name)
{
return $this->_select_one($this->get_table_name(), ['name' => $name, 'id_user' => $id_user]);
}
/**
* Return table name.
*/

View File

@ -13,6 +13,8 @@ namespace models;
class SmsStop extends StandardModel
{
const SMS_STOP_TAG = 'SMS_STOP';
/**
* Return a smsstop by his number and user.
*

View File

@ -161,6 +161,16 @@
'</div>' +
'</div>';
}
else if (field.type == 'textarea')
{
html += '<div class="form-group">' +
'<label>' + field.title + '</label>' +
'<p class="italic small help">' + field.description + '</p>' +
'<div class="form-group">' +
'<textarea name="adapter_data[' + field.name + ']" class="form-control" ' + (field.required ? 'required' : '') + ' >' + (field.default_value ? field.default_value : '') + '</textarea>' +
'</div>' +
'</div>';
}
else
{
html += '<div class="form-group">' +

View File

@ -225,6 +225,16 @@
'</div>' +
'</div>';
}
else if (field.type == 'textarea')
{
html += '<div class="form-group">' +
'<label>' + field.title + '</label>' +
'<p class="italic small help">' + field.description + '</p>' +
'<div class="form-group">' +
'<textarea name="adapter_data[' + field.name + ']" class="form-control" ' + (field.required ? 'required' : '') + ' >' + (value ? value : '') + '</textarea>' +
'</div>' +
'</div>';
}
else
{
html += '' +

View File

@ -112,6 +112,30 @@
</div>
</div>
</div>
<?php if (ENABLE_URL_SHORTENER) { ?>
<div class="col-xs-12 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><i class="fa fa-link fa-fw"></i> Support du raccourcisseur d'URL</h4>
</div>
<div class="panel-body">
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'shorten_url', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
<div class="form-group">
<label>Raccourcir automatiquement les liens HTTP(S) dans les SMS : </label>
<select name="setting_value" class="form-control">
<option value="0">Non</option>
<option value="1" <?php echo $_SESSION['user']['settings']['shorten_url'] ? 'selected' : ''; ?>>Oui</option>
</select>
</div>
<div class="text-center">
<button class="btn btn-success">Mettre à jour les données</button>
</div>
</form>
</div>
</div>
</div>
<?php } ?>
<div class="col-xs-12 col-md-6">
<div class="panel panel-default">
@ -179,6 +203,47 @@
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><i class="fa fa-ban fa-fw"></i> Activation des réponses automatiques aux SMS-STOP</h4>
</div>
<div class="panel-body">
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'smsstop_respond', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
<div class="form-group">
<label>Réponses automatiques aux SMS STOP activées : </label>
<select name="setting_value" class="form-control">
<option value="0">Non</option>
<option value="1" <?php echo $_SESSION['user']['settings']['smsstop_respond'] ? 'selected' : ''; ?>>Oui</option>
</select>
</div>
<div class="text-center">
<button class="btn btn-success">Mettre à jour les données</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title"><i class="fa fa-comments-o fa-fw"></i> Texte de réponse aux SMS-STOP</h4>
</div>
<div class="panel-body">
<form action="<?php echo \descartes\Router::url('Setting', 'update', ['setting_name' => 'smsstop_response', 'csrf' => $_SESSION['csrf']]); ?>" method="POST">
<div class="form-group">
<label>Texte des réponses automatiques aux SMS-STOP : </label>
<input name="setting_value" class="form-control" value="<?php $this->s($_SESSION['user']['settings']['smsstop_response'] ?? ''); ?>" />
</div>
<div class="text-center">
<button class="btn btn-success">Mettre à jour les données</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="panel panel-default">
<div class="panel-heading">