Compare commits
No commits in common. "master" and "v3.5.2" have entirely different histories.
|
@ -3,7 +3,3 @@ RewriteRule ^assets - [L]
|
||||||
RewriteRule ^.well-known - [L]
|
RewriteRule ^.well-known - [L]
|
||||||
RewriteRule ^data/public/ - [L]
|
RewriteRule ^data/public/ - [L]
|
||||||
RewriteRule . index.php
|
RewriteRule . index.php
|
||||||
|
|
||||||
<IfModule headers_module>
|
|
||||||
Header always set Content-Security-Policy "upgrade-insecure-requests;"
|
|
||||||
</ifModule>
|
|
||||||
|
|
|
@ -79,11 +79,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -124,9 +119,9 @@ interface AdapterInterface
|
||||||
* @param array $medias : Array of medias to link to the MMS, [['http_url' => HTTP public url of the media et 'local_uri' => local uri to media file]]
|
* @param array $medias : Array of medias to link to the MMS, [['http_url' => HTTP public url of the media et 'local_uri' => local uri to media file]]
|
||||||
*
|
*
|
||||||
* @return array : [
|
* @return array : [
|
||||||
* bool 'error' => false if no error, true else,
|
* bool 'error' => false if no error, true else
|
||||||
* ?string 'error_message' => null if no error, else error message,
|
* ?string 'error_message' => null if no error, else error message
|
||||||
* array 'uid' => Uid of the sms created on success,
|
* array 'uid' => Uid of the sms created on success
|
||||||
* ]
|
* ]
|
||||||
*/
|
*/
|
||||||
public function send(string $destination, string $text, bool $flash = false, bool $mms = false, array $medias = []): array;
|
public function send(string $destination, string $text, bool $flash = false, bool $mms = false, array $medias = []): array;
|
||||||
|
@ -157,15 +152,6 @@ 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', 'limit_reached'
|
|
||||||
*/
|
|
||||||
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.
|
||||||
*
|
*
|
||||||
|
@ -207,7 +193,7 @@ interface AdapterInterface
|
||||||
* ]
|
* ]
|
||||||
* ]
|
* ]
|
||||||
*/
|
*/
|
||||||
public static function inbound_call_callback(): array;
|
public function inbound_call_callback(): array;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called on reception of a end call notification.
|
* Method called on reception of a end call notification.
|
||||||
|
@ -221,5 +207,5 @@ interface AdapterInterface
|
||||||
* ]
|
* ]
|
||||||
* ]
|
* ]
|
||||||
*/
|
*/
|
||||||
public static function end_call_callback(): array;
|
public function end_call_callback(): array;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,14 +111,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -234,16 +226,6 @@ 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;
|
||||||
|
@ -259,12 +241,12 @@ namespace adapters;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,14 +121,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -196,14 +188,13 @@ namespace adapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
$command_parts = [
|
$command_parts = [
|
||||||
'LC_ALL=C',
|
|
||||||
'gammu',
|
'gammu',
|
||||||
'--config',
|
'--config',
|
||||||
escapeshellarg($this->data['config_file']),
|
escapeshellarg($this->data['config_file']),
|
||||||
'sendsms',
|
'sendsms',
|
||||||
'TEXT',
|
'TEXT',
|
||||||
escapeshellarg($destination),
|
escapeshellarg($destination),
|
||||||
'-textutf8',
|
'-text',
|
||||||
escapeshellarg($text),
|
escapeshellarg($text),
|
||||||
'-validity',
|
'-validity',
|
||||||
'MAX',
|
'MAX',
|
||||||
|
@ -280,7 +271,6 @@ namespace adapters;
|
||||||
$command_parts = [
|
$command_parts = [
|
||||||
PWD . '/bin/gammu_get_unread_sms.py',
|
PWD . '/bin/gammu_get_unread_sms.py',
|
||||||
escapeshellarg($this->data['config_file']),
|
escapeshellarg($this->data['config_file']),
|
||||||
'--delete'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$return = $this->exec_command($command_parts);
|
$return = $this->exec_command($command_parts);
|
||||||
|
@ -310,16 +300,6 @@ 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
|
||||||
|
@ -336,12 +316,12 @@ namespace adapters;
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -358,10 +338,7 @@ namespace adapters;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The command returns 123 on failed execution (even if SIM is already unlocked), and returns 0 if unlock was successful
|
|
||||||
// We can directly return true if command was succesful
|
|
||||||
$command_parts = [
|
$command_parts = [
|
||||||
'LC_ALL=C',
|
|
||||||
'gammu',
|
'gammu',
|
||||||
'--config',
|
'--config',
|
||||||
escapeshellarg($this->data['config_file']),
|
escapeshellarg($this->data['config_file']),
|
||||||
|
@ -371,15 +348,9 @@ namespace adapters;
|
||||||
];
|
];
|
||||||
|
|
||||||
$result = $this->exec_command($command_parts);
|
$result = $this->exec_command($command_parts);
|
||||||
if (0 === $result['return'])
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check security status
|
//Check security status
|
||||||
// The command returns 0 regardless of the SIM security state
|
|
||||||
$command_parts = [
|
$command_parts = [
|
||||||
'LC_ALL=C',
|
|
||||||
'gammu',
|
'gammu',
|
||||||
'--config',
|
'--config',
|
||||||
escapeshellarg($this->data['config_file']),
|
escapeshellarg($this->data['config_file']),
|
||||||
|
|
|
@ -209,14 +209,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -362,16 +354,6 @@ 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
|
||||||
|
@ -508,12 +490,12 @@ class KannelAdapter implements AdapterInterface
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,14 +174,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -333,16 +325,6 @@ 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
|
||||||
|
@ -486,12 +468,12 @@ class OctopushShortcodeAdapter implements AdapterInterface
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,14 +173,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -325,16 +317,6 @@ 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
|
||||||
|
@ -479,12 +461,12 @@ class OctopushVirtualNumberAdapter implements AdapterInterface
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,511 +0,0 @@
|
||||||
<?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 adapters;
|
|
||||||
|
|
||||||
use DateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Odyssey Messaging SMS service
|
|
||||||
*/
|
|
||||||
class OdysseyMessagingAdapter implements AdapterInterface
|
|
||||||
{
|
|
||||||
const EVENT_TYPES = [
|
|
||||||
'OPT_OUT' => 1,
|
|
||||||
'SYSTEM_ERROR' => 2,
|
|
||||||
'END_OF_ITEM' => 3,
|
|
||||||
'END_OF_JOB' => 4,
|
|
||||||
'JOB_STATUS_CHANGED' => 5,
|
|
||||||
'REAL_TIME_STATUS' => 6,
|
|
||||||
'RETRIEVE_FILE' => 7,
|
|
||||||
'INBOUND_SMS' => 8,
|
|
||||||
'ITEM_STATUS_CHANGED' => 9,
|
|
||||||
'DATA_COLLECTION_FILLED' => 10,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data used to configure interaction with the implemented service. (e.g : Api credentials, ports numbers, etc.).
|
|
||||||
*/
|
|
||||||
private $data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Odyssey login.
|
|
||||||
*/
|
|
||||||
private $login;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Odyssey password.
|
|
||||||
*/
|
|
||||||
private $password;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sender name to use instead of shortcode.
|
|
||||||
*/
|
|
||||||
private $sender;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Odyssey api baseurl.
|
|
||||||
*/
|
|
||||||
private $api_url = 'https://api.odyssey-services.fr/api/v1';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter constructor, called when instanciated by RaspiSMS.
|
|
||||||
*
|
|
||||||
* @param json string $data : JSON string of the data to configure interaction with the implemented service
|
|
||||||
*/
|
|
||||||
public function __construct(string $data)
|
|
||||||
{
|
|
||||||
$this->data = json_decode($data, true);
|
|
||||||
|
|
||||||
$this->login = $this->data['login'];
|
|
||||||
$this->password = $this->data['password'];
|
|
||||||
|
|
||||||
$this->sender = $this->data['sender'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classname of the adapter.
|
|
||||||
*/
|
|
||||||
public static function meta_classname(): string
|
|
||||||
{
|
|
||||||
return __CLASS__;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uniq name of the adapter
|
|
||||||
* It should be the classname of the adapter un snakecase.
|
|
||||||
*/
|
|
||||||
public static function meta_uid(): string
|
|
||||||
{
|
|
||||||
return 'odyssey_messaging_adapter';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should this adapter be hidden in user interface for phone creation and
|
|
||||||
* available to creation through API only.
|
|
||||||
*/
|
|
||||||
public static function meta_hidden(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Should this adapter data be hidden after creation
|
|
||||||
* this help to prevent API credentials to other service leak if an attacker gain access to RaspiSMS through user credentials.
|
|
||||||
*/
|
|
||||||
public static function meta_hide_data(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the adapter.
|
|
||||||
* It should probably be the name of the service it adapt (e.g : Gammu SMSD, OVH SMS, SIM800L, etc.).
|
|
||||||
*/
|
|
||||||
public static function meta_name(): string
|
|
||||||
{
|
|
||||||
return 'Odyssey Messaging';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of the adapter.
|
|
||||||
* A short description of the service the adapter implements.
|
|
||||||
*/
|
|
||||||
public static function meta_description(): string
|
|
||||||
{
|
|
||||||
return '
|
|
||||||
Envoi de SMS avec <a target="_blank" href="https://www.odyssey-messaging.com/">Odyssey Messaging</a>.
|
|
||||||
Pour plus d\'information sur l\'utilisation de ce type de téléphone, reportez-vous à <a href="https://documentation.raspisms.fr/users/adapters/odyssey_messaging.html" target="_blank">la documentation sur le téléphone "Odyssey Messaging".</a>
|
|
||||||
';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of entries we want in data for the adapter.
|
|
||||||
*
|
|
||||||
* @return array : Every line is a field as an array with keys : name, title, description, required
|
|
||||||
*/
|
|
||||||
public static function meta_data_fields(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
'name' => 'login',
|
|
||||||
'title' => 'Odyssey login',
|
|
||||||
'description' => 'Login du compte Odyssey à employer.',
|
|
||||||
'required' => true,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'password',
|
|
||||||
'title' => 'Mot de passe',
|
|
||||||
'description' => 'Mot de passe du compte Odyssey à employer.',
|
|
||||||
'required' => true,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'name' => 'sender',
|
|
||||||
'title' => 'Nom de l\'expéditeur',
|
|
||||||
'description' => 'Nom de l\'expéditeur à afficher à la place du numéro (11 caractères max).<br/>
|
|
||||||
<b>Laissez vide pour ne pas utiliser d\'expéditeur nommé.</b><br/>
|
|
||||||
<b>Si vous utilisez un expéditeur nommé, le destinataire ne pourra pas répondre.</b>',
|
|
||||||
'required' => false,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the implemented service support reading smss.
|
|
||||||
*/
|
|
||||||
public static function meta_support_read(): bool
|
|
||||||
{
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
public static function meta_support_flash(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the implemented service support status change.
|
|
||||||
*/
|
|
||||||
public static function meta_support_status_change(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the implemented service support reception callback.
|
|
||||||
*/
|
|
||||||
public static function meta_support_reception(): bool
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the implemented service support mms reception.
|
|
||||||
*/
|
|
||||||
public static function meta_support_mms_reception(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does the implemented service support mms sending.
|
|
||||||
*/
|
|
||||||
public static function meta_support_mms_sending(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function meta_support_inbound_call_callback(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function meta_support_end_call_callback(): bool
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send(string $destination, string $text, bool $flash = false, bool $mms = false, array $medias = []): array
|
|
||||||
{
|
|
||||||
$response = [
|
|
||||||
'error' => false,
|
|
||||||
'error_message' => null,
|
|
||||||
'uid' => null,
|
|
||||||
];
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
$credentials = base64_encode($this->login . ':' . $this->password);
|
|
||||||
$headers = [
|
|
||||||
'Authorization: Basic ' . $credentials,
|
|
||||||
'Content-Type: application/json',
|
|
||||||
];
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'JobType' => 'SMS',
|
|
||||||
'Text' => $text,
|
|
||||||
'TrackingID' => uniqid(),
|
|
||||||
'AdhocRecipients' => [['Name' => uniqid(), 'Address' => str_replace('+', '00', $destination)]],
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($this->sender)
|
|
||||||
{
|
|
||||||
$data['Parameter'] = ['Sender' => $this->sender, 'Media' => 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = json_encode($data);
|
|
||||||
|
|
||||||
$endpoint = $this->api_url . '/SMSJobs';
|
|
||||||
|
|
||||||
$curl = curl_init();
|
|
||||||
curl_setopt($curl, CURLOPT_URL, $endpoint);
|
|
||||||
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
|
||||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
|
||||||
curl_setopt($curl, CURLOPT_POST, true);
|
|
||||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
|
||||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
|
||||||
|
|
||||||
$curl_response = curl_exec($curl);
|
|
||||||
$http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
||||||
curl_close($curl);
|
|
||||||
|
|
||||||
if (false === $curl_response)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'HTTP query failed.';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response_decode = json_decode($curl_response, true);
|
|
||||||
if (null === $response_decode)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Invalid JSON for response.';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (200 !== $http_code)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Response indicate error : ' . $response_decode['Message'] . ' -> """' . json_encode($response_decode['ModelState']) . '""" AND HTTP CODE -> ' . $http_code;
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$uid = $response_decode['JobNumber'] ?? false;
|
|
||||||
if (!$uid)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Cannot extract SMS uid';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response['uid'] = $uid;
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
catch (\Throwable $t)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = $t->getMessage();
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function read(): array
|
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if ($this->data['sender'] && (mb_strlen($this->data['sender']) < 3 || mb_strlen($this->data['sender'] > 11)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($this->data['sms_type']) && !in_array($this->data['sms_type'], ['premium', 'low cost']))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$credentials = base64_encode($this->login . ':' . $this->password);
|
|
||||||
$headers = [
|
|
||||||
'Authorization: Basic ' . $credentials,
|
|
||||||
'Content-Type: application/json',
|
|
||||||
];
|
|
||||||
|
|
||||||
//Check service name
|
|
||||||
$endpoint = $this->api_url . '/JobTypes';
|
|
||||||
$curl = curl_init();
|
|
||||||
curl_setopt($curl, CURLOPT_URL, $endpoint);
|
|
||||||
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
|
||||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
|
||||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
|
||||||
$response = curl_exec($curl);
|
|
||||||
$http_code = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
|
||||||
curl_close($curl);
|
|
||||||
|
|
||||||
if (200 !== $http_code)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (\Throwable $t)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function status_change_callback()
|
|
||||||
{
|
|
||||||
header('Connection: close');
|
|
||||||
header('Content-Encoding: none');
|
|
||||||
header('Content-Length: 0');
|
|
||||||
|
|
||||||
$input = file_get_contents('php://input');
|
|
||||||
$content = json_decode($input, true);
|
|
||||||
if (null === $content)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$event_type = $content['EventType'] ?? false;
|
|
||||||
if ($event_type != self::EVENT_TYPES['ITEM_STATUS_CHANGED'])
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$uid = $content['JobNumber'] ?? false;
|
|
||||||
$status = $content['Outcome'] ?? false;
|
|
||||||
|
|
||||||
if (false === $uid || false === $status)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($status)
|
|
||||||
{
|
|
||||||
case 'S':
|
|
||||||
$status = \models\Sended::STATUS_DELIVERED;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'B':
|
|
||||||
$status = \models\Sended::STATUS_UNKNOWN;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
$status = \models\Sended::STATUS_FAILED;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['uid' => $uid, 'status' => $status];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function reception_callback(): array
|
|
||||||
{
|
|
||||||
$response = [
|
|
||||||
'error' => false,
|
|
||||||
'error_message' => null,
|
|
||||||
'sms' => null,
|
|
||||||
];
|
|
||||||
|
|
||||||
header('Connection: close');
|
|
||||||
header('Content-Encoding: none');
|
|
||||||
header('Content-Length: 0');
|
|
||||||
|
|
||||||
$input = file_get_contents('php://input');
|
|
||||||
$content = json_decode($input, true);
|
|
||||||
if (null === $content)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Cannot read input data from callback request.';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$event_type = $content['EventType'] ?? false;
|
|
||||||
if ($event_type != self::EVENT_TYPES['INBOUND_SMS'])
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Invalid event type : ' . $event_type . '.';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$number = $content['From'] ?? false;
|
|
||||||
$text = $content['Message'] ?? false;
|
|
||||||
$at = $content['EventDateTime'] ?? false;
|
|
||||||
|
|
||||||
if (!$number || !$text || !$at)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'One required data of the callback is missing.';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$matches = null;
|
|
||||||
$match = preg_match('#/Date\(([0-9]+)\+([0-9]+)\)/#', $at, $matches);
|
|
||||||
$timestamp = ($matches[1] ?? null);
|
|
||||||
if (!$match || !$timestamp)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Invalid date.';
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$at = DateTime::createFromFormat('U', $timestamp / 1000);
|
|
||||||
$at = $at->format('Y-m-d H:i:s');
|
|
||||||
|
|
||||||
$origin = \controllers\internals\Tool::parse_phone($number);
|
|
||||||
if (!$origin)
|
|
||||||
{
|
|
||||||
$response['error'] = true;
|
|
||||||
$response['error_message'] = 'Invalid origin number : ' . $number;
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
$response['sms'] = [
|
|
||||||
'at' => $at,
|
|
||||||
'text' => $text,
|
|
||||||
'origin' => $origin,
|
|
||||||
];
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -162,14 +162,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -335,16 +327,6 @@ 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
|
||||||
|
@ -406,12 +388,12 @@ namespace adapters;
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,14 +166,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -325,16 +317,6 @@ 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
|
||||||
|
@ -396,12 +378,12 @@ namespace adapters;
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,14 +116,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -295,16 +287,6 @@ 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;
|
||||||
|
@ -351,7 +333,7 @@ namespace adapters;
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
$response = [
|
$response = [
|
||||||
'error' => false,
|
'error' => false,
|
||||||
|
@ -380,7 +362,7 @@ namespace adapters;
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
$response = [
|
$response = [
|
||||||
'error' => false,
|
'error' => false,
|
||||||
|
|
|
@ -160,14 +160,6 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
@ -303,16 +295,6 @@ 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
|
||||||
|
@ -374,12 +356,12 @@ class TwilioVirtualNumberAdapter implements AdapterInterface
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function inbound_call_callback(): array
|
public function inbound_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function end_call_callback(): array
|
public function end_call_callback(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,8 +311,7 @@ footer img
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SCHEDULEDS */
|
/* SCHEDULEDS */
|
||||||
.add-number-button,
|
.add-number-button
|
||||||
.add-phone-limit-button
|
|
||||||
{
|
{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: #DADFE1;
|
color: #DADFE1;
|
||||||
|
@ -320,8 +319,7 @@ footer img
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-number-button:hover,
|
.add-number-button:hover
|
||||||
.add-phone-limit-button:hover
|
|
||||||
{
|
{
|
||||||
color: #3498DB;
|
color: #3498DB;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -375,8 +373,7 @@ footer img
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scheduleds-number-groupe,
|
.scheduleds-number-groupe
|
||||||
.phone-limits-group
|
|
||||||
{
|
{
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
|
@ -386,8 +383,7 @@ footer img
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scheduleds-number-groupe-remove,
|
.scheduleds-number-groupe-remove
|
||||||
.phone-limits-group-remove
|
|
||||||
{
|
{
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: 15px;
|
||||||
|
@ -395,8 +391,7 @@ footer img
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scheduleds-number-groupe-remove:hover,
|
.scheduleds-number-groupe-remove:hover
|
||||||
.phone-limits-group-remove:hover
|
|
||||||
{
|
{
|
||||||
color: #555;
|
color: #555;
|
||||||
}
|
}
|
||||||
|
@ -471,16 +466,6 @@ footer img
|
||||||
color: #9b2420;
|
color: #9b2420;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PREVIEW CONTACT */
|
|
||||||
.preview-contact-name
|
|
||||||
{
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview-contact-number
|
|
||||||
{
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* PHONE */
|
/* PHONE */
|
||||||
#adapter-data-container
|
#adapter-data-container
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
/*!
|
/*!
|
||||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||||
*/
|
*/
|
||||||
/* FONT PATH
|
/* FONT PATH
|
||||||
* -------------------------- */
|
* -------------------------- */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'FontAwesome';
|
font-family: 'FontAwesome';
|
||||||
src: url('../fonts/fontawesome-webfont.eot?v=4.7.0');
|
src: url('../fonts/fontawesome-webfont.eot?v=4.2.0');
|
||||||
src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');
|
src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.2.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.2.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.2.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
@ -64,19 +64,6 @@
|
||||||
border: solid 0.08em #eeeeee;
|
border: solid 0.08em #eeeeee;
|
||||||
border-radius: .1em;
|
border-radius: .1em;
|
||||||
}
|
}
|
||||||
.fa-pull-left {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.fa-pull-right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
.fa.fa-pull-left {
|
|
||||||
margin-right: .3em;
|
|
||||||
}
|
|
||||||
.fa.fa-pull-right {
|
|
||||||
margin-left: .3em;
|
|
||||||
}
|
|
||||||
/* Deprecated as of 4.4.0 */
|
|
||||||
.pull-right {
|
.pull-right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
@ -93,10 +80,6 @@
|
||||||
-webkit-animation: fa-spin 2s infinite linear;
|
-webkit-animation: fa-spin 2s infinite linear;
|
||||||
animation: fa-spin 2s infinite linear;
|
animation: fa-spin 2s infinite linear;
|
||||||
}
|
}
|
||||||
.fa-pulse {
|
|
||||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
|
||||||
animation: fa-spin 1s infinite steps(8);
|
|
||||||
}
|
|
||||||
@-webkit-keyframes fa-spin {
|
@-webkit-keyframes fa-spin {
|
||||||
0% {
|
0% {
|
||||||
-webkit-transform: rotate(0deg);
|
-webkit-transform: rotate(0deg);
|
||||||
|
@ -118,31 +101,31 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fa-rotate-90 {
|
.fa-rotate-90 {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);
|
||||||
-webkit-transform: rotate(90deg);
|
-webkit-transform: rotate(90deg);
|
||||||
-ms-transform: rotate(90deg);
|
-ms-transform: rotate(90deg);
|
||||||
transform: rotate(90deg);
|
transform: rotate(90deg);
|
||||||
}
|
}
|
||||||
.fa-rotate-180 {
|
.fa-rotate-180 {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);
|
||||||
-webkit-transform: rotate(180deg);
|
-webkit-transform: rotate(180deg);
|
||||||
-ms-transform: rotate(180deg);
|
-ms-transform: rotate(180deg);
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
.fa-rotate-270 {
|
.fa-rotate-270 {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
|
||||||
-webkit-transform: rotate(270deg);
|
-webkit-transform: rotate(270deg);
|
||||||
-ms-transform: rotate(270deg);
|
-ms-transform: rotate(270deg);
|
||||||
transform: rotate(270deg);
|
transform: rotate(270deg);
|
||||||
}
|
}
|
||||||
.fa-flip-horizontal {
|
.fa-flip-horizontal {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);
|
||||||
-webkit-transform: scale(-1, 1);
|
-webkit-transform: scale(-1, 1);
|
||||||
-ms-transform: scale(-1, 1);
|
-ms-transform: scale(-1, 1);
|
||||||
transform: scale(-1, 1);
|
transform: scale(-1, 1);
|
||||||
}
|
}
|
||||||
.fa-flip-vertical {
|
.fa-flip-vertical {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);
|
||||||
-webkit-transform: scale(1, -1);
|
-webkit-transform: scale(1, -1);
|
||||||
-ms-transform: scale(1, -1);
|
-ms-transform: scale(1, -1);
|
||||||
transform: scale(1, -1);
|
transform: scale(1, -1);
|
||||||
|
@ -627,7 +610,6 @@
|
||||||
.fa-twitter:before {
|
.fa-twitter:before {
|
||||||
content: "\f099";
|
content: "\f099";
|
||||||
}
|
}
|
||||||
.fa-facebook-f:before,
|
|
||||||
.fa-facebook:before {
|
.fa-facebook:before {
|
||||||
content: "\f09a";
|
content: "\f09a";
|
||||||
}
|
}
|
||||||
|
@ -640,7 +622,6 @@
|
||||||
.fa-credit-card:before {
|
.fa-credit-card:before {
|
||||||
content: "\f09d";
|
content: "\f09d";
|
||||||
}
|
}
|
||||||
.fa-feed:before,
|
|
||||||
.fa-rss:before {
|
.fa-rss:before {
|
||||||
content: "\f09e";
|
content: "\f09e";
|
||||||
}
|
}
|
||||||
|
@ -1278,8 +1259,7 @@
|
||||||
.fa-male:before {
|
.fa-male:before {
|
||||||
content: "\f183";
|
content: "\f183";
|
||||||
}
|
}
|
||||||
.fa-gittip:before,
|
.fa-gittip:before {
|
||||||
.fa-gratipay:before {
|
|
||||||
content: "\f184";
|
content: "\f184";
|
||||||
}
|
}
|
||||||
.fa-sun-o:before {
|
.fa-sun-o:before {
|
||||||
|
@ -1383,7 +1363,7 @@
|
||||||
.fa-digg:before {
|
.fa-digg:before {
|
||||||
content: "\f1a6";
|
content: "\f1a6";
|
||||||
}
|
}
|
||||||
.fa-pied-piper-pp:before {
|
.fa-pied-piper:before {
|
||||||
content: "\f1a7";
|
content: "\f1a7";
|
||||||
}
|
}
|
||||||
.fa-pied-piper-alt:before {
|
.fa-pied-piper-alt:before {
|
||||||
|
@ -1509,7 +1489,6 @@
|
||||||
content: "\f1ce";
|
content: "\f1ce";
|
||||||
}
|
}
|
||||||
.fa-ra:before,
|
.fa-ra:before,
|
||||||
.fa-resistance:before,
|
|
||||||
.fa-rebel:before {
|
.fa-rebel:before {
|
||||||
content: "\f1d0";
|
content: "\f1d0";
|
||||||
}
|
}
|
||||||
|
@ -1523,8 +1502,6 @@
|
||||||
.fa-git:before {
|
.fa-git:before {
|
||||||
content: "\f1d3";
|
content: "\f1d3";
|
||||||
}
|
}
|
||||||
.fa-y-combinator-square:before,
|
|
||||||
.fa-yc-square:before,
|
|
||||||
.fa-hacker-news:before {
|
.fa-hacker-news:before {
|
||||||
content: "\f1d4";
|
content: "\f1d4";
|
||||||
}
|
}
|
||||||
|
@ -1693,645 +1670,3 @@
|
||||||
.fa-meanpath:before {
|
.fa-meanpath:before {
|
||||||
content: "\f20c";
|
content: "\f20c";
|
||||||
}
|
}
|
||||||
.fa-buysellads:before {
|
|
||||||
content: "\f20d";
|
|
||||||
}
|
|
||||||
.fa-connectdevelop:before {
|
|
||||||
content: "\f20e";
|
|
||||||
}
|
|
||||||
.fa-dashcube:before {
|
|
||||||
content: "\f210";
|
|
||||||
}
|
|
||||||
.fa-forumbee:before {
|
|
||||||
content: "\f211";
|
|
||||||
}
|
|
||||||
.fa-leanpub:before {
|
|
||||||
content: "\f212";
|
|
||||||
}
|
|
||||||
.fa-sellsy:before {
|
|
||||||
content: "\f213";
|
|
||||||
}
|
|
||||||
.fa-shirtsinbulk:before {
|
|
||||||
content: "\f214";
|
|
||||||
}
|
|
||||||
.fa-simplybuilt:before {
|
|
||||||
content: "\f215";
|
|
||||||
}
|
|
||||||
.fa-skyatlas:before {
|
|
||||||
content: "\f216";
|
|
||||||
}
|
|
||||||
.fa-cart-plus:before {
|
|
||||||
content: "\f217";
|
|
||||||
}
|
|
||||||
.fa-cart-arrow-down:before {
|
|
||||||
content: "\f218";
|
|
||||||
}
|
|
||||||
.fa-diamond:before {
|
|
||||||
content: "\f219";
|
|
||||||
}
|
|
||||||
.fa-ship:before {
|
|
||||||
content: "\f21a";
|
|
||||||
}
|
|
||||||
.fa-user-secret:before {
|
|
||||||
content: "\f21b";
|
|
||||||
}
|
|
||||||
.fa-motorcycle:before {
|
|
||||||
content: "\f21c";
|
|
||||||
}
|
|
||||||
.fa-street-view:before {
|
|
||||||
content: "\f21d";
|
|
||||||
}
|
|
||||||
.fa-heartbeat:before {
|
|
||||||
content: "\f21e";
|
|
||||||
}
|
|
||||||
.fa-venus:before {
|
|
||||||
content: "\f221";
|
|
||||||
}
|
|
||||||
.fa-mars:before {
|
|
||||||
content: "\f222";
|
|
||||||
}
|
|
||||||
.fa-mercury:before {
|
|
||||||
content: "\f223";
|
|
||||||
}
|
|
||||||
.fa-intersex:before,
|
|
||||||
.fa-transgender:before {
|
|
||||||
content: "\f224";
|
|
||||||
}
|
|
||||||
.fa-transgender-alt:before {
|
|
||||||
content: "\f225";
|
|
||||||
}
|
|
||||||
.fa-venus-double:before {
|
|
||||||
content: "\f226";
|
|
||||||
}
|
|
||||||
.fa-mars-double:before {
|
|
||||||
content: "\f227";
|
|
||||||
}
|
|
||||||
.fa-venus-mars:before {
|
|
||||||
content: "\f228";
|
|
||||||
}
|
|
||||||
.fa-mars-stroke:before {
|
|
||||||
content: "\f229";
|
|
||||||
}
|
|
||||||
.fa-mars-stroke-v:before {
|
|
||||||
content: "\f22a";
|
|
||||||
}
|
|
||||||
.fa-mars-stroke-h:before {
|
|
||||||
content: "\f22b";
|
|
||||||
}
|
|
||||||
.fa-neuter:before {
|
|
||||||
content: "\f22c";
|
|
||||||
}
|
|
||||||
.fa-genderless:before {
|
|
||||||
content: "\f22d";
|
|
||||||
}
|
|
||||||
.fa-facebook-official:before {
|
|
||||||
content: "\f230";
|
|
||||||
}
|
|
||||||
.fa-pinterest-p:before {
|
|
||||||
content: "\f231";
|
|
||||||
}
|
|
||||||
.fa-whatsapp:before {
|
|
||||||
content: "\f232";
|
|
||||||
}
|
|
||||||
.fa-server:before {
|
|
||||||
content: "\f233";
|
|
||||||
}
|
|
||||||
.fa-user-plus:before {
|
|
||||||
content: "\f234";
|
|
||||||
}
|
|
||||||
.fa-user-times:before {
|
|
||||||
content: "\f235";
|
|
||||||
}
|
|
||||||
.fa-hotel:before,
|
|
||||||
.fa-bed:before {
|
|
||||||
content: "\f236";
|
|
||||||
}
|
|
||||||
.fa-viacoin:before {
|
|
||||||
content: "\f237";
|
|
||||||
}
|
|
||||||
.fa-train:before {
|
|
||||||
content: "\f238";
|
|
||||||
}
|
|
||||||
.fa-subway:before {
|
|
||||||
content: "\f239";
|
|
||||||
}
|
|
||||||
.fa-medium:before {
|
|
||||||
content: "\f23a";
|
|
||||||
}
|
|
||||||
.fa-yc:before,
|
|
||||||
.fa-y-combinator:before {
|
|
||||||
content: "\f23b";
|
|
||||||
}
|
|
||||||
.fa-optin-monster:before {
|
|
||||||
content: "\f23c";
|
|
||||||
}
|
|
||||||
.fa-opencart:before {
|
|
||||||
content: "\f23d";
|
|
||||||
}
|
|
||||||
.fa-expeditedssl:before {
|
|
||||||
content: "\f23e";
|
|
||||||
}
|
|
||||||
.fa-battery-4:before,
|
|
||||||
.fa-battery:before,
|
|
||||||
.fa-battery-full:before {
|
|
||||||
content: "\f240";
|
|
||||||
}
|
|
||||||
.fa-battery-3:before,
|
|
||||||
.fa-battery-three-quarters:before {
|
|
||||||
content: "\f241";
|
|
||||||
}
|
|
||||||
.fa-battery-2:before,
|
|
||||||
.fa-battery-half:before {
|
|
||||||
content: "\f242";
|
|
||||||
}
|
|
||||||
.fa-battery-1:before,
|
|
||||||
.fa-battery-quarter:before {
|
|
||||||
content: "\f243";
|
|
||||||
}
|
|
||||||
.fa-battery-0:before,
|
|
||||||
.fa-battery-empty:before {
|
|
||||||
content: "\f244";
|
|
||||||
}
|
|
||||||
.fa-mouse-pointer:before {
|
|
||||||
content: "\f245";
|
|
||||||
}
|
|
||||||
.fa-i-cursor:before {
|
|
||||||
content: "\f246";
|
|
||||||
}
|
|
||||||
.fa-object-group:before {
|
|
||||||
content: "\f247";
|
|
||||||
}
|
|
||||||
.fa-object-ungroup:before {
|
|
||||||
content: "\f248";
|
|
||||||
}
|
|
||||||
.fa-sticky-note:before {
|
|
||||||
content: "\f249";
|
|
||||||
}
|
|
||||||
.fa-sticky-note-o:before {
|
|
||||||
content: "\f24a";
|
|
||||||
}
|
|
||||||
.fa-cc-jcb:before {
|
|
||||||
content: "\f24b";
|
|
||||||
}
|
|
||||||
.fa-cc-diners-club:before {
|
|
||||||
content: "\f24c";
|
|
||||||
}
|
|
||||||
.fa-clone:before {
|
|
||||||
content: "\f24d";
|
|
||||||
}
|
|
||||||
.fa-balance-scale:before {
|
|
||||||
content: "\f24e";
|
|
||||||
}
|
|
||||||
.fa-hourglass-o:before {
|
|
||||||
content: "\f250";
|
|
||||||
}
|
|
||||||
.fa-hourglass-1:before,
|
|
||||||
.fa-hourglass-start:before {
|
|
||||||
content: "\f251";
|
|
||||||
}
|
|
||||||
.fa-hourglass-2:before,
|
|
||||||
.fa-hourglass-half:before {
|
|
||||||
content: "\f252";
|
|
||||||
}
|
|
||||||
.fa-hourglass-3:before,
|
|
||||||
.fa-hourglass-end:before {
|
|
||||||
content: "\f253";
|
|
||||||
}
|
|
||||||
.fa-hourglass:before {
|
|
||||||
content: "\f254";
|
|
||||||
}
|
|
||||||
.fa-hand-grab-o:before,
|
|
||||||
.fa-hand-rock-o:before {
|
|
||||||
content: "\f255";
|
|
||||||
}
|
|
||||||
.fa-hand-stop-o:before,
|
|
||||||
.fa-hand-paper-o:before {
|
|
||||||
content: "\f256";
|
|
||||||
}
|
|
||||||
.fa-hand-scissors-o:before {
|
|
||||||
content: "\f257";
|
|
||||||
}
|
|
||||||
.fa-hand-lizard-o:before {
|
|
||||||
content: "\f258";
|
|
||||||
}
|
|
||||||
.fa-hand-spock-o:before {
|
|
||||||
content: "\f259";
|
|
||||||
}
|
|
||||||
.fa-hand-pointer-o:before {
|
|
||||||
content: "\f25a";
|
|
||||||
}
|
|
||||||
.fa-hand-peace-o:before {
|
|
||||||
content: "\f25b";
|
|
||||||
}
|
|
||||||
.fa-trademark:before {
|
|
||||||
content: "\f25c";
|
|
||||||
}
|
|
||||||
.fa-registered:before {
|
|
||||||
content: "\f25d";
|
|
||||||
}
|
|
||||||
.fa-creative-commons:before {
|
|
||||||
content: "\f25e";
|
|
||||||
}
|
|
||||||
.fa-gg:before {
|
|
||||||
content: "\f260";
|
|
||||||
}
|
|
||||||
.fa-gg-circle:before {
|
|
||||||
content: "\f261";
|
|
||||||
}
|
|
||||||
.fa-tripadvisor:before {
|
|
||||||
content: "\f262";
|
|
||||||
}
|
|
||||||
.fa-odnoklassniki:before {
|
|
||||||
content: "\f263";
|
|
||||||
}
|
|
||||||
.fa-odnoklassniki-square:before {
|
|
||||||
content: "\f264";
|
|
||||||
}
|
|
||||||
.fa-get-pocket:before {
|
|
||||||
content: "\f265";
|
|
||||||
}
|
|
||||||
.fa-wikipedia-w:before {
|
|
||||||
content: "\f266";
|
|
||||||
}
|
|
||||||
.fa-safari:before {
|
|
||||||
content: "\f267";
|
|
||||||
}
|
|
||||||
.fa-chrome:before {
|
|
||||||
content: "\f268";
|
|
||||||
}
|
|
||||||
.fa-firefox:before {
|
|
||||||
content: "\f269";
|
|
||||||
}
|
|
||||||
.fa-opera:before {
|
|
||||||
content: "\f26a";
|
|
||||||
}
|
|
||||||
.fa-internet-explorer:before {
|
|
||||||
content: "\f26b";
|
|
||||||
}
|
|
||||||
.fa-tv:before,
|
|
||||||
.fa-television:before {
|
|
||||||
content: "\f26c";
|
|
||||||
}
|
|
||||||
.fa-contao:before {
|
|
||||||
content: "\f26d";
|
|
||||||
}
|
|
||||||
.fa-500px:before {
|
|
||||||
content: "\f26e";
|
|
||||||
}
|
|
||||||
.fa-amazon:before {
|
|
||||||
content: "\f270";
|
|
||||||
}
|
|
||||||
.fa-calendar-plus-o:before {
|
|
||||||
content: "\f271";
|
|
||||||
}
|
|
||||||
.fa-calendar-minus-o:before {
|
|
||||||
content: "\f272";
|
|
||||||
}
|
|
||||||
.fa-calendar-times-o:before {
|
|
||||||
content: "\f273";
|
|
||||||
}
|
|
||||||
.fa-calendar-check-o:before {
|
|
||||||
content: "\f274";
|
|
||||||
}
|
|
||||||
.fa-industry:before {
|
|
||||||
content: "\f275";
|
|
||||||
}
|
|
||||||
.fa-map-pin:before {
|
|
||||||
content: "\f276";
|
|
||||||
}
|
|
||||||
.fa-map-signs:before {
|
|
||||||
content: "\f277";
|
|
||||||
}
|
|
||||||
.fa-map-o:before {
|
|
||||||
content: "\f278";
|
|
||||||
}
|
|
||||||
.fa-map:before {
|
|
||||||
content: "\f279";
|
|
||||||
}
|
|
||||||
.fa-commenting:before {
|
|
||||||
content: "\f27a";
|
|
||||||
}
|
|
||||||
.fa-commenting-o:before {
|
|
||||||
content: "\f27b";
|
|
||||||
}
|
|
||||||
.fa-houzz:before {
|
|
||||||
content: "\f27c";
|
|
||||||
}
|
|
||||||
.fa-vimeo:before {
|
|
||||||
content: "\f27d";
|
|
||||||
}
|
|
||||||
.fa-black-tie:before {
|
|
||||||
content: "\f27e";
|
|
||||||
}
|
|
||||||
.fa-fonticons:before {
|
|
||||||
content: "\f280";
|
|
||||||
}
|
|
||||||
.fa-reddit-alien:before {
|
|
||||||
content: "\f281";
|
|
||||||
}
|
|
||||||
.fa-edge:before {
|
|
||||||
content: "\f282";
|
|
||||||
}
|
|
||||||
.fa-credit-card-alt:before {
|
|
||||||
content: "\f283";
|
|
||||||
}
|
|
||||||
.fa-codiepie:before {
|
|
||||||
content: "\f284";
|
|
||||||
}
|
|
||||||
.fa-modx:before {
|
|
||||||
content: "\f285";
|
|
||||||
}
|
|
||||||
.fa-fort-awesome:before {
|
|
||||||
content: "\f286";
|
|
||||||
}
|
|
||||||
.fa-usb:before {
|
|
||||||
content: "\f287";
|
|
||||||
}
|
|
||||||
.fa-product-hunt:before {
|
|
||||||
content: "\f288";
|
|
||||||
}
|
|
||||||
.fa-mixcloud:before {
|
|
||||||
content: "\f289";
|
|
||||||
}
|
|
||||||
.fa-scribd:before {
|
|
||||||
content: "\f28a";
|
|
||||||
}
|
|
||||||
.fa-pause-circle:before {
|
|
||||||
content: "\f28b";
|
|
||||||
}
|
|
||||||
.fa-pause-circle-o:before {
|
|
||||||
content: "\f28c";
|
|
||||||
}
|
|
||||||
.fa-stop-circle:before {
|
|
||||||
content: "\f28d";
|
|
||||||
}
|
|
||||||
.fa-stop-circle-o:before {
|
|
||||||
content: "\f28e";
|
|
||||||
}
|
|
||||||
.fa-shopping-bag:before {
|
|
||||||
content: "\f290";
|
|
||||||
}
|
|
||||||
.fa-shopping-basket:before {
|
|
||||||
content: "\f291";
|
|
||||||
}
|
|
||||||
.fa-hashtag:before {
|
|
||||||
content: "\f292";
|
|
||||||
}
|
|
||||||
.fa-bluetooth:before {
|
|
||||||
content: "\f293";
|
|
||||||
}
|
|
||||||
.fa-bluetooth-b:before {
|
|
||||||
content: "\f294";
|
|
||||||
}
|
|
||||||
.fa-percent:before {
|
|
||||||
content: "\f295";
|
|
||||||
}
|
|
||||||
.fa-gitlab:before {
|
|
||||||
content: "\f296";
|
|
||||||
}
|
|
||||||
.fa-wpbeginner:before {
|
|
||||||
content: "\f297";
|
|
||||||
}
|
|
||||||
.fa-wpforms:before {
|
|
||||||
content: "\f298";
|
|
||||||
}
|
|
||||||
.fa-envira:before {
|
|
||||||
content: "\f299";
|
|
||||||
}
|
|
||||||
.fa-universal-access:before {
|
|
||||||
content: "\f29a";
|
|
||||||
}
|
|
||||||
.fa-wheelchair-alt:before {
|
|
||||||
content: "\f29b";
|
|
||||||
}
|
|
||||||
.fa-question-circle-o:before {
|
|
||||||
content: "\f29c";
|
|
||||||
}
|
|
||||||
.fa-blind:before {
|
|
||||||
content: "\f29d";
|
|
||||||
}
|
|
||||||
.fa-audio-description:before {
|
|
||||||
content: "\f29e";
|
|
||||||
}
|
|
||||||
.fa-volume-control-phone:before {
|
|
||||||
content: "\f2a0";
|
|
||||||
}
|
|
||||||
.fa-braille:before {
|
|
||||||
content: "\f2a1";
|
|
||||||
}
|
|
||||||
.fa-assistive-listening-systems:before {
|
|
||||||
content: "\f2a2";
|
|
||||||
}
|
|
||||||
.fa-asl-interpreting:before,
|
|
||||||
.fa-american-sign-language-interpreting:before {
|
|
||||||
content: "\f2a3";
|
|
||||||
}
|
|
||||||
.fa-deafness:before,
|
|
||||||
.fa-hard-of-hearing:before,
|
|
||||||
.fa-deaf:before {
|
|
||||||
content: "\f2a4";
|
|
||||||
}
|
|
||||||
.fa-glide:before {
|
|
||||||
content: "\f2a5";
|
|
||||||
}
|
|
||||||
.fa-glide-g:before {
|
|
||||||
content: "\f2a6";
|
|
||||||
}
|
|
||||||
.fa-signing:before,
|
|
||||||
.fa-sign-language:before {
|
|
||||||
content: "\f2a7";
|
|
||||||
}
|
|
||||||
.fa-low-vision:before {
|
|
||||||
content: "\f2a8";
|
|
||||||
}
|
|
||||||
.fa-viadeo:before {
|
|
||||||
content: "\f2a9";
|
|
||||||
}
|
|
||||||
.fa-viadeo-square:before {
|
|
||||||
content: "\f2aa";
|
|
||||||
}
|
|
||||||
.fa-snapchat:before {
|
|
||||||
content: "\f2ab";
|
|
||||||
}
|
|
||||||
.fa-snapchat-ghost:before {
|
|
||||||
content: "\f2ac";
|
|
||||||
}
|
|
||||||
.fa-snapchat-square:before {
|
|
||||||
content: "\f2ad";
|
|
||||||
}
|
|
||||||
.fa-pied-piper:before {
|
|
||||||
content: "\f2ae";
|
|
||||||
}
|
|
||||||
.fa-first-order:before {
|
|
||||||
content: "\f2b0";
|
|
||||||
}
|
|
||||||
.fa-yoast:before {
|
|
||||||
content: "\f2b1";
|
|
||||||
}
|
|
||||||
.fa-themeisle:before {
|
|
||||||
content: "\f2b2";
|
|
||||||
}
|
|
||||||
.fa-google-plus-circle:before,
|
|
||||||
.fa-google-plus-official:before {
|
|
||||||
content: "\f2b3";
|
|
||||||
}
|
|
||||||
.fa-fa:before,
|
|
||||||
.fa-font-awesome:before {
|
|
||||||
content: "\f2b4";
|
|
||||||
}
|
|
||||||
.fa-handshake-o:before {
|
|
||||||
content: "\f2b5";
|
|
||||||
}
|
|
||||||
.fa-envelope-open:before {
|
|
||||||
content: "\f2b6";
|
|
||||||
}
|
|
||||||
.fa-envelope-open-o:before {
|
|
||||||
content: "\f2b7";
|
|
||||||
}
|
|
||||||
.fa-linode:before {
|
|
||||||
content: "\f2b8";
|
|
||||||
}
|
|
||||||
.fa-address-book:before {
|
|
||||||
content: "\f2b9";
|
|
||||||
}
|
|
||||||
.fa-address-book-o:before {
|
|
||||||
content: "\f2ba";
|
|
||||||
}
|
|
||||||
.fa-vcard:before,
|
|
||||||
.fa-address-card:before {
|
|
||||||
content: "\f2bb";
|
|
||||||
}
|
|
||||||
.fa-vcard-o:before,
|
|
||||||
.fa-address-card-o:before {
|
|
||||||
content: "\f2bc";
|
|
||||||
}
|
|
||||||
.fa-user-circle:before {
|
|
||||||
content: "\f2bd";
|
|
||||||
}
|
|
||||||
.fa-user-circle-o:before {
|
|
||||||
content: "\f2be";
|
|
||||||
}
|
|
||||||
.fa-user-o:before {
|
|
||||||
content: "\f2c0";
|
|
||||||
}
|
|
||||||
.fa-id-badge:before {
|
|
||||||
content: "\f2c1";
|
|
||||||
}
|
|
||||||
.fa-drivers-license:before,
|
|
||||||
.fa-id-card:before {
|
|
||||||
content: "\f2c2";
|
|
||||||
}
|
|
||||||
.fa-drivers-license-o:before,
|
|
||||||
.fa-id-card-o:before {
|
|
||||||
content: "\f2c3";
|
|
||||||
}
|
|
||||||
.fa-quora:before {
|
|
||||||
content: "\f2c4";
|
|
||||||
}
|
|
||||||
.fa-free-code-camp:before {
|
|
||||||
content: "\f2c5";
|
|
||||||
}
|
|
||||||
.fa-telegram:before {
|
|
||||||
content: "\f2c6";
|
|
||||||
}
|
|
||||||
.fa-thermometer-4:before,
|
|
||||||
.fa-thermometer:before,
|
|
||||||
.fa-thermometer-full:before {
|
|
||||||
content: "\f2c7";
|
|
||||||
}
|
|
||||||
.fa-thermometer-3:before,
|
|
||||||
.fa-thermometer-three-quarters:before {
|
|
||||||
content: "\f2c8";
|
|
||||||
}
|
|
||||||
.fa-thermometer-2:before,
|
|
||||||
.fa-thermometer-half:before {
|
|
||||||
content: "\f2c9";
|
|
||||||
}
|
|
||||||
.fa-thermometer-1:before,
|
|
||||||
.fa-thermometer-quarter:before {
|
|
||||||
content: "\f2ca";
|
|
||||||
}
|
|
||||||
.fa-thermometer-0:before,
|
|
||||||
.fa-thermometer-empty:before {
|
|
||||||
content: "\f2cb";
|
|
||||||
}
|
|
||||||
.fa-shower:before {
|
|
||||||
content: "\f2cc";
|
|
||||||
}
|
|
||||||
.fa-bathtub:before,
|
|
||||||
.fa-s15:before,
|
|
||||||
.fa-bath:before {
|
|
||||||
content: "\f2cd";
|
|
||||||
}
|
|
||||||
.fa-podcast:before {
|
|
||||||
content: "\f2ce";
|
|
||||||
}
|
|
||||||
.fa-window-maximize:before {
|
|
||||||
content: "\f2d0";
|
|
||||||
}
|
|
||||||
.fa-window-minimize:before {
|
|
||||||
content: "\f2d1";
|
|
||||||
}
|
|
||||||
.fa-window-restore:before {
|
|
||||||
content: "\f2d2";
|
|
||||||
}
|
|
||||||
.fa-times-rectangle:before,
|
|
||||||
.fa-window-close:before {
|
|
||||||
content: "\f2d3";
|
|
||||||
}
|
|
||||||
.fa-times-rectangle-o:before,
|
|
||||||
.fa-window-close-o:before {
|
|
||||||
content: "\f2d4";
|
|
||||||
}
|
|
||||||
.fa-bandcamp:before {
|
|
||||||
content: "\f2d5";
|
|
||||||
}
|
|
||||||
.fa-grav:before {
|
|
||||||
content: "\f2d6";
|
|
||||||
}
|
|
||||||
.fa-etsy:before {
|
|
||||||
content: "\f2d7";
|
|
||||||
}
|
|
||||||
.fa-imdb:before {
|
|
||||||
content: "\f2d8";
|
|
||||||
}
|
|
||||||
.fa-ravelry:before {
|
|
||||||
content: "\f2d9";
|
|
||||||
}
|
|
||||||
.fa-eercast:before {
|
|
||||||
content: "\f2da";
|
|
||||||
}
|
|
||||||
.fa-microchip:before {
|
|
||||||
content: "\f2db";
|
|
||||||
}
|
|
||||||
.fa-snowflake-o:before {
|
|
||||||
content: "\f2dc";
|
|
||||||
}
|
|
||||||
.fa-superpowers:before {
|
|
||||||
content: "\f2dd";
|
|
||||||
}
|
|
||||||
.fa-wpexplorer:before {
|
|
||||||
content: "\f2de";
|
|
||||||
}
|
|
||||||
.fa-meetup:before {
|
|
||||||
content: "\f2e0";
|
|
||||||
}
|
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
.sr-only-focusable:active,
|
|
||||||
.sr-only-focusable:focus {
|
|
||||||
position: static;
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
margin: 0;
|
|
||||||
overflow: visible;
|
|
||||||
clip: auto;
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 280 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -7,15 +7,6 @@
|
||||||
border-radius: .1em;
|
border-radius: .1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{fa-css-prefix}-pull-left { float: left; }
|
|
||||||
.@{fa-css-prefix}-pull-right { float: right; }
|
|
||||||
|
|
||||||
.@{fa-css-prefix} {
|
|
||||||
&.@{fa-css-prefix}-pull-left { margin-right: .3em; }
|
|
||||||
&.@{fa-css-prefix}-pull-right { margin-left: .3em; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deprecated as of 4.4.0 */
|
|
||||||
.pull-right { float: right; }
|
.pull-right { float: right; }
|
||||||
.pull-left { float: left; }
|
.pull-left { float: left; }
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
|
|
||||||
.@{fa-css-prefix} {
|
.@{fa-css-prefix} {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
|
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,8 +11,7 @@
|
||||||
@import "fixed-width.less";
|
@import "fixed-width.less";
|
||||||
@import "list.less";
|
@import "list.less";
|
||||||
@import "bordered-pulled.less";
|
@import "bordered-pulled.less";
|
||||||
@import "animated.less";
|
@import "spinning.less";
|
||||||
@import "rotated-flipped.less";
|
@import "rotated-flipped.less";
|
||||||
@import "stacked.less";
|
@import "stacked.less";
|
||||||
@import "icons.less";
|
@import "icons.less";
|
||||||
@import "screen-reader.less";
|
|
||||||
|
|
|
@ -158,12 +158,10 @@
|
||||||
.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
|
.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; }
|
||||||
.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
|
.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; }
|
||||||
.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
|
.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; }
|
||||||
.@{fa-css-prefix}-facebook-f:before,
|
|
||||||
.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
|
.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; }
|
||||||
.@{fa-css-prefix}-github:before { content: @fa-var-github; }
|
.@{fa-css-prefix}-github:before { content: @fa-var-github; }
|
||||||
.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
|
.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; }
|
||||||
.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
|
.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; }
|
||||||
.@{fa-css-prefix}-feed:before,
|
|
||||||
.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
|
.@{fa-css-prefix}-rss:before { content: @fa-var-rss; }
|
||||||
.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
|
.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; }
|
||||||
.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
|
.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; }
|
||||||
|
@ -399,8 +397,7 @@
|
||||||
.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
|
.@{fa-css-prefix}-trello:before { content: @fa-var-trello; }
|
||||||
.@{fa-css-prefix}-female:before { content: @fa-var-female; }
|
.@{fa-css-prefix}-female:before { content: @fa-var-female; }
|
||||||
.@{fa-css-prefix}-male:before { content: @fa-var-male; }
|
.@{fa-css-prefix}-male:before { content: @fa-var-male; }
|
||||||
.@{fa-css-prefix}-gittip:before,
|
.@{fa-css-prefix}-gittip:before { content: @fa-var-gittip; }
|
||||||
.@{fa-css-prefix}-gratipay:before { content: @fa-var-gratipay; }
|
|
||||||
.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
|
.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; }
|
||||||
.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
|
.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; }
|
||||||
.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
|
.@{fa-css-prefix}-archive:before { content: @fa-var-archive; }
|
||||||
|
@ -438,7 +435,7 @@
|
||||||
.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
|
.@{fa-css-prefix}-stumbleupon:before { content: @fa-var-stumbleupon; }
|
||||||
.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
|
.@{fa-css-prefix}-delicious:before { content: @fa-var-delicious; }
|
||||||
.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
|
.@{fa-css-prefix}-digg:before { content: @fa-var-digg; }
|
||||||
.@{fa-css-prefix}-pied-piper-pp:before { content: @fa-var-pied-piper-pp; }
|
.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
|
||||||
.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
|
.@{fa-css-prefix}-pied-piper-alt:before { content: @fa-var-pied-piper-alt; }
|
||||||
.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
|
.@{fa-css-prefix}-drupal:before { content: @fa-var-drupal; }
|
||||||
.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
|
.@{fa-css-prefix}-joomla:before { content: @fa-var-joomla; }
|
||||||
|
@ -488,14 +485,11 @@
|
||||||
.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
|
.@{fa-css-prefix}-life-ring:before { content: @fa-var-life-ring; }
|
||||||
.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
|
.@{fa-css-prefix}-circle-o-notch:before { content: @fa-var-circle-o-notch; }
|
||||||
.@{fa-css-prefix}-ra:before,
|
.@{fa-css-prefix}-ra:before,
|
||||||
.@{fa-css-prefix}-resistance:before,
|
|
||||||
.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
|
.@{fa-css-prefix}-rebel:before { content: @fa-var-rebel; }
|
||||||
.@{fa-css-prefix}-ge:before,
|
.@{fa-css-prefix}-ge:before,
|
||||||
.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
|
.@{fa-css-prefix}-empire:before { content: @fa-var-empire; }
|
||||||
.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
|
.@{fa-css-prefix}-git-square:before { content: @fa-var-git-square; }
|
||||||
.@{fa-css-prefix}-git:before { content: @fa-var-git; }
|
.@{fa-css-prefix}-git:before { content: @fa-var-git; }
|
||||||
.@{fa-css-prefix}-y-combinator-square:before,
|
|
||||||
.@{fa-css-prefix}-yc-square:before,
|
|
||||||
.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
|
.@{fa-css-prefix}-hacker-news:before { content: @fa-var-hacker-news; }
|
||||||
.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
|
.@{fa-css-prefix}-tencent-weibo:before { content: @fa-var-tencent-weibo; }
|
||||||
.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
|
.@{fa-css-prefix}-qq:before { content: @fa-var-qq; }
|
||||||
|
@ -556,234 +550,3 @@
|
||||||
.@{fa-css-prefix}-sheqel:before,
|
.@{fa-css-prefix}-sheqel:before,
|
||||||
.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
|
.@{fa-css-prefix}-ils:before { content: @fa-var-ils; }
|
||||||
.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
|
.@{fa-css-prefix}-meanpath:before { content: @fa-var-meanpath; }
|
||||||
.@{fa-css-prefix}-buysellads:before { content: @fa-var-buysellads; }
|
|
||||||
.@{fa-css-prefix}-connectdevelop:before { content: @fa-var-connectdevelop; }
|
|
||||||
.@{fa-css-prefix}-dashcube:before { content: @fa-var-dashcube; }
|
|
||||||
.@{fa-css-prefix}-forumbee:before { content: @fa-var-forumbee; }
|
|
||||||
.@{fa-css-prefix}-leanpub:before { content: @fa-var-leanpub; }
|
|
||||||
.@{fa-css-prefix}-sellsy:before { content: @fa-var-sellsy; }
|
|
||||||
.@{fa-css-prefix}-shirtsinbulk:before { content: @fa-var-shirtsinbulk; }
|
|
||||||
.@{fa-css-prefix}-simplybuilt:before { content: @fa-var-simplybuilt; }
|
|
||||||
.@{fa-css-prefix}-skyatlas:before { content: @fa-var-skyatlas; }
|
|
||||||
.@{fa-css-prefix}-cart-plus:before { content: @fa-var-cart-plus; }
|
|
||||||
.@{fa-css-prefix}-cart-arrow-down:before { content: @fa-var-cart-arrow-down; }
|
|
||||||
.@{fa-css-prefix}-diamond:before { content: @fa-var-diamond; }
|
|
||||||
.@{fa-css-prefix}-ship:before { content: @fa-var-ship; }
|
|
||||||
.@{fa-css-prefix}-user-secret:before { content: @fa-var-user-secret; }
|
|
||||||
.@{fa-css-prefix}-motorcycle:before { content: @fa-var-motorcycle; }
|
|
||||||
.@{fa-css-prefix}-street-view:before { content: @fa-var-street-view; }
|
|
||||||
.@{fa-css-prefix}-heartbeat:before { content: @fa-var-heartbeat; }
|
|
||||||
.@{fa-css-prefix}-venus:before { content: @fa-var-venus; }
|
|
||||||
.@{fa-css-prefix}-mars:before { content: @fa-var-mars; }
|
|
||||||
.@{fa-css-prefix}-mercury:before { content: @fa-var-mercury; }
|
|
||||||
.@{fa-css-prefix}-intersex:before,
|
|
||||||
.@{fa-css-prefix}-transgender:before { content: @fa-var-transgender; }
|
|
||||||
.@{fa-css-prefix}-transgender-alt:before { content: @fa-var-transgender-alt; }
|
|
||||||
.@{fa-css-prefix}-venus-double:before { content: @fa-var-venus-double; }
|
|
||||||
.@{fa-css-prefix}-mars-double:before { content: @fa-var-mars-double; }
|
|
||||||
.@{fa-css-prefix}-venus-mars:before { content: @fa-var-venus-mars; }
|
|
||||||
.@{fa-css-prefix}-mars-stroke:before { content: @fa-var-mars-stroke; }
|
|
||||||
.@{fa-css-prefix}-mars-stroke-v:before { content: @fa-var-mars-stroke-v; }
|
|
||||||
.@{fa-css-prefix}-mars-stroke-h:before { content: @fa-var-mars-stroke-h; }
|
|
||||||
.@{fa-css-prefix}-neuter:before { content: @fa-var-neuter; }
|
|
||||||
.@{fa-css-prefix}-genderless:before { content: @fa-var-genderless; }
|
|
||||||
.@{fa-css-prefix}-facebook-official:before { content: @fa-var-facebook-official; }
|
|
||||||
.@{fa-css-prefix}-pinterest-p:before { content: @fa-var-pinterest-p; }
|
|
||||||
.@{fa-css-prefix}-whatsapp:before { content: @fa-var-whatsapp; }
|
|
||||||
.@{fa-css-prefix}-server:before { content: @fa-var-server; }
|
|
||||||
.@{fa-css-prefix}-user-plus:before { content: @fa-var-user-plus; }
|
|
||||||
.@{fa-css-prefix}-user-times:before { content: @fa-var-user-times; }
|
|
||||||
.@{fa-css-prefix}-hotel:before,
|
|
||||||
.@{fa-css-prefix}-bed:before { content: @fa-var-bed; }
|
|
||||||
.@{fa-css-prefix}-viacoin:before { content: @fa-var-viacoin; }
|
|
||||||
.@{fa-css-prefix}-train:before { content: @fa-var-train; }
|
|
||||||
.@{fa-css-prefix}-subway:before { content: @fa-var-subway; }
|
|
||||||
.@{fa-css-prefix}-medium:before { content: @fa-var-medium; }
|
|
||||||
.@{fa-css-prefix}-yc:before,
|
|
||||||
.@{fa-css-prefix}-y-combinator:before { content: @fa-var-y-combinator; }
|
|
||||||
.@{fa-css-prefix}-optin-monster:before { content: @fa-var-optin-monster; }
|
|
||||||
.@{fa-css-prefix}-opencart:before { content: @fa-var-opencart; }
|
|
||||||
.@{fa-css-prefix}-expeditedssl:before { content: @fa-var-expeditedssl; }
|
|
||||||
.@{fa-css-prefix}-battery-4:before,
|
|
||||||
.@{fa-css-prefix}-battery:before,
|
|
||||||
.@{fa-css-prefix}-battery-full:before { content: @fa-var-battery-full; }
|
|
||||||
.@{fa-css-prefix}-battery-3:before,
|
|
||||||
.@{fa-css-prefix}-battery-three-quarters:before { content: @fa-var-battery-three-quarters; }
|
|
||||||
.@{fa-css-prefix}-battery-2:before,
|
|
||||||
.@{fa-css-prefix}-battery-half:before { content: @fa-var-battery-half; }
|
|
||||||
.@{fa-css-prefix}-battery-1:before,
|
|
||||||
.@{fa-css-prefix}-battery-quarter:before { content: @fa-var-battery-quarter; }
|
|
||||||
.@{fa-css-prefix}-battery-0:before,
|
|
||||||
.@{fa-css-prefix}-battery-empty:before { content: @fa-var-battery-empty; }
|
|
||||||
.@{fa-css-prefix}-mouse-pointer:before { content: @fa-var-mouse-pointer; }
|
|
||||||
.@{fa-css-prefix}-i-cursor:before { content: @fa-var-i-cursor; }
|
|
||||||
.@{fa-css-prefix}-object-group:before { content: @fa-var-object-group; }
|
|
||||||
.@{fa-css-prefix}-object-ungroup:before { content: @fa-var-object-ungroup; }
|
|
||||||
.@{fa-css-prefix}-sticky-note:before { content: @fa-var-sticky-note; }
|
|
||||||
.@{fa-css-prefix}-sticky-note-o:before { content: @fa-var-sticky-note-o; }
|
|
||||||
.@{fa-css-prefix}-cc-jcb:before { content: @fa-var-cc-jcb; }
|
|
||||||
.@{fa-css-prefix}-cc-diners-club:before { content: @fa-var-cc-diners-club; }
|
|
||||||
.@{fa-css-prefix}-clone:before { content: @fa-var-clone; }
|
|
||||||
.@{fa-css-prefix}-balance-scale:before { content: @fa-var-balance-scale; }
|
|
||||||
.@{fa-css-prefix}-hourglass-o:before { content: @fa-var-hourglass-o; }
|
|
||||||
.@{fa-css-prefix}-hourglass-1:before,
|
|
||||||
.@{fa-css-prefix}-hourglass-start:before { content: @fa-var-hourglass-start; }
|
|
||||||
.@{fa-css-prefix}-hourglass-2:before,
|
|
||||||
.@{fa-css-prefix}-hourglass-half:before { content: @fa-var-hourglass-half; }
|
|
||||||
.@{fa-css-prefix}-hourglass-3:before,
|
|
||||||
.@{fa-css-prefix}-hourglass-end:before { content: @fa-var-hourglass-end; }
|
|
||||||
.@{fa-css-prefix}-hourglass:before { content: @fa-var-hourglass; }
|
|
||||||
.@{fa-css-prefix}-hand-grab-o:before,
|
|
||||||
.@{fa-css-prefix}-hand-rock-o:before { content: @fa-var-hand-rock-o; }
|
|
||||||
.@{fa-css-prefix}-hand-stop-o:before,
|
|
||||||
.@{fa-css-prefix}-hand-paper-o:before { content: @fa-var-hand-paper-o; }
|
|
||||||
.@{fa-css-prefix}-hand-scissors-o:before { content: @fa-var-hand-scissors-o; }
|
|
||||||
.@{fa-css-prefix}-hand-lizard-o:before { content: @fa-var-hand-lizard-o; }
|
|
||||||
.@{fa-css-prefix}-hand-spock-o:before { content: @fa-var-hand-spock-o; }
|
|
||||||
.@{fa-css-prefix}-hand-pointer-o:before { content: @fa-var-hand-pointer-o; }
|
|
||||||
.@{fa-css-prefix}-hand-peace-o:before { content: @fa-var-hand-peace-o; }
|
|
||||||
.@{fa-css-prefix}-trademark:before { content: @fa-var-trademark; }
|
|
||||||
.@{fa-css-prefix}-registered:before { content: @fa-var-registered; }
|
|
||||||
.@{fa-css-prefix}-creative-commons:before { content: @fa-var-creative-commons; }
|
|
||||||
.@{fa-css-prefix}-gg:before { content: @fa-var-gg; }
|
|
||||||
.@{fa-css-prefix}-gg-circle:before { content: @fa-var-gg-circle; }
|
|
||||||
.@{fa-css-prefix}-tripadvisor:before { content: @fa-var-tripadvisor; }
|
|
||||||
.@{fa-css-prefix}-odnoklassniki:before { content: @fa-var-odnoklassniki; }
|
|
||||||
.@{fa-css-prefix}-odnoklassniki-square:before { content: @fa-var-odnoklassniki-square; }
|
|
||||||
.@{fa-css-prefix}-get-pocket:before { content: @fa-var-get-pocket; }
|
|
||||||
.@{fa-css-prefix}-wikipedia-w:before { content: @fa-var-wikipedia-w; }
|
|
||||||
.@{fa-css-prefix}-safari:before { content: @fa-var-safari; }
|
|
||||||
.@{fa-css-prefix}-chrome:before { content: @fa-var-chrome; }
|
|
||||||
.@{fa-css-prefix}-firefox:before { content: @fa-var-firefox; }
|
|
||||||
.@{fa-css-prefix}-opera:before { content: @fa-var-opera; }
|
|
||||||
.@{fa-css-prefix}-internet-explorer:before { content: @fa-var-internet-explorer; }
|
|
||||||
.@{fa-css-prefix}-tv:before,
|
|
||||||
.@{fa-css-prefix}-television:before { content: @fa-var-television; }
|
|
||||||
.@{fa-css-prefix}-contao:before { content: @fa-var-contao; }
|
|
||||||
.@{fa-css-prefix}-500px:before { content: @fa-var-500px; }
|
|
||||||
.@{fa-css-prefix}-amazon:before { content: @fa-var-amazon; }
|
|
||||||
.@{fa-css-prefix}-calendar-plus-o:before { content: @fa-var-calendar-plus-o; }
|
|
||||||
.@{fa-css-prefix}-calendar-minus-o:before { content: @fa-var-calendar-minus-o; }
|
|
||||||
.@{fa-css-prefix}-calendar-times-o:before { content: @fa-var-calendar-times-o; }
|
|
||||||
.@{fa-css-prefix}-calendar-check-o:before { content: @fa-var-calendar-check-o; }
|
|
||||||
.@{fa-css-prefix}-industry:before { content: @fa-var-industry; }
|
|
||||||
.@{fa-css-prefix}-map-pin:before { content: @fa-var-map-pin; }
|
|
||||||
.@{fa-css-prefix}-map-signs:before { content: @fa-var-map-signs; }
|
|
||||||
.@{fa-css-prefix}-map-o:before { content: @fa-var-map-o; }
|
|
||||||
.@{fa-css-prefix}-map:before { content: @fa-var-map; }
|
|
||||||
.@{fa-css-prefix}-commenting:before { content: @fa-var-commenting; }
|
|
||||||
.@{fa-css-prefix}-commenting-o:before { content: @fa-var-commenting-o; }
|
|
||||||
.@{fa-css-prefix}-houzz:before { content: @fa-var-houzz; }
|
|
||||||
.@{fa-css-prefix}-vimeo:before { content: @fa-var-vimeo; }
|
|
||||||
.@{fa-css-prefix}-black-tie:before { content: @fa-var-black-tie; }
|
|
||||||
.@{fa-css-prefix}-fonticons:before { content: @fa-var-fonticons; }
|
|
||||||
.@{fa-css-prefix}-reddit-alien:before { content: @fa-var-reddit-alien; }
|
|
||||||
.@{fa-css-prefix}-edge:before { content: @fa-var-edge; }
|
|
||||||
.@{fa-css-prefix}-credit-card-alt:before { content: @fa-var-credit-card-alt; }
|
|
||||||
.@{fa-css-prefix}-codiepie:before { content: @fa-var-codiepie; }
|
|
||||||
.@{fa-css-prefix}-modx:before { content: @fa-var-modx; }
|
|
||||||
.@{fa-css-prefix}-fort-awesome:before { content: @fa-var-fort-awesome; }
|
|
||||||
.@{fa-css-prefix}-usb:before { content: @fa-var-usb; }
|
|
||||||
.@{fa-css-prefix}-product-hunt:before { content: @fa-var-product-hunt; }
|
|
||||||
.@{fa-css-prefix}-mixcloud:before { content: @fa-var-mixcloud; }
|
|
||||||
.@{fa-css-prefix}-scribd:before { content: @fa-var-scribd; }
|
|
||||||
.@{fa-css-prefix}-pause-circle:before { content: @fa-var-pause-circle; }
|
|
||||||
.@{fa-css-prefix}-pause-circle-o:before { content: @fa-var-pause-circle-o; }
|
|
||||||
.@{fa-css-prefix}-stop-circle:before { content: @fa-var-stop-circle; }
|
|
||||||
.@{fa-css-prefix}-stop-circle-o:before { content: @fa-var-stop-circle-o; }
|
|
||||||
.@{fa-css-prefix}-shopping-bag:before { content: @fa-var-shopping-bag; }
|
|
||||||
.@{fa-css-prefix}-shopping-basket:before { content: @fa-var-shopping-basket; }
|
|
||||||
.@{fa-css-prefix}-hashtag:before { content: @fa-var-hashtag; }
|
|
||||||
.@{fa-css-prefix}-bluetooth:before { content: @fa-var-bluetooth; }
|
|
||||||
.@{fa-css-prefix}-bluetooth-b:before { content: @fa-var-bluetooth-b; }
|
|
||||||
.@{fa-css-prefix}-percent:before { content: @fa-var-percent; }
|
|
||||||
.@{fa-css-prefix}-gitlab:before { content: @fa-var-gitlab; }
|
|
||||||
.@{fa-css-prefix}-wpbeginner:before { content: @fa-var-wpbeginner; }
|
|
||||||
.@{fa-css-prefix}-wpforms:before { content: @fa-var-wpforms; }
|
|
||||||
.@{fa-css-prefix}-envira:before { content: @fa-var-envira; }
|
|
||||||
.@{fa-css-prefix}-universal-access:before { content: @fa-var-universal-access; }
|
|
||||||
.@{fa-css-prefix}-wheelchair-alt:before { content: @fa-var-wheelchair-alt; }
|
|
||||||
.@{fa-css-prefix}-question-circle-o:before { content: @fa-var-question-circle-o; }
|
|
||||||
.@{fa-css-prefix}-blind:before { content: @fa-var-blind; }
|
|
||||||
.@{fa-css-prefix}-audio-description:before { content: @fa-var-audio-description; }
|
|
||||||
.@{fa-css-prefix}-volume-control-phone:before { content: @fa-var-volume-control-phone; }
|
|
||||||
.@{fa-css-prefix}-braille:before { content: @fa-var-braille; }
|
|
||||||
.@{fa-css-prefix}-assistive-listening-systems:before { content: @fa-var-assistive-listening-systems; }
|
|
||||||
.@{fa-css-prefix}-asl-interpreting:before,
|
|
||||||
.@{fa-css-prefix}-american-sign-language-interpreting:before { content: @fa-var-american-sign-language-interpreting; }
|
|
||||||
.@{fa-css-prefix}-deafness:before,
|
|
||||||
.@{fa-css-prefix}-hard-of-hearing:before,
|
|
||||||
.@{fa-css-prefix}-deaf:before { content: @fa-var-deaf; }
|
|
||||||
.@{fa-css-prefix}-glide:before { content: @fa-var-glide; }
|
|
||||||
.@{fa-css-prefix}-glide-g:before { content: @fa-var-glide-g; }
|
|
||||||
.@{fa-css-prefix}-signing:before,
|
|
||||||
.@{fa-css-prefix}-sign-language:before { content: @fa-var-sign-language; }
|
|
||||||
.@{fa-css-prefix}-low-vision:before { content: @fa-var-low-vision; }
|
|
||||||
.@{fa-css-prefix}-viadeo:before { content: @fa-var-viadeo; }
|
|
||||||
.@{fa-css-prefix}-viadeo-square:before { content: @fa-var-viadeo-square; }
|
|
||||||
.@{fa-css-prefix}-snapchat:before { content: @fa-var-snapchat; }
|
|
||||||
.@{fa-css-prefix}-snapchat-ghost:before { content: @fa-var-snapchat-ghost; }
|
|
||||||
.@{fa-css-prefix}-snapchat-square:before { content: @fa-var-snapchat-square; }
|
|
||||||
.@{fa-css-prefix}-pied-piper:before { content: @fa-var-pied-piper; }
|
|
||||||
.@{fa-css-prefix}-first-order:before { content: @fa-var-first-order; }
|
|
||||||
.@{fa-css-prefix}-yoast:before { content: @fa-var-yoast; }
|
|
||||||
.@{fa-css-prefix}-themeisle:before { content: @fa-var-themeisle; }
|
|
||||||
.@{fa-css-prefix}-google-plus-circle:before,
|
|
||||||
.@{fa-css-prefix}-google-plus-official:before { content: @fa-var-google-plus-official; }
|
|
||||||
.@{fa-css-prefix}-fa:before,
|
|
||||||
.@{fa-css-prefix}-font-awesome:before { content: @fa-var-font-awesome; }
|
|
||||||
.@{fa-css-prefix}-handshake-o:before { content: @fa-var-handshake-o; }
|
|
||||||
.@{fa-css-prefix}-envelope-open:before { content: @fa-var-envelope-open; }
|
|
||||||
.@{fa-css-prefix}-envelope-open-o:before { content: @fa-var-envelope-open-o; }
|
|
||||||
.@{fa-css-prefix}-linode:before { content: @fa-var-linode; }
|
|
||||||
.@{fa-css-prefix}-address-book:before { content: @fa-var-address-book; }
|
|
||||||
.@{fa-css-prefix}-address-book-o:before { content: @fa-var-address-book-o; }
|
|
||||||
.@{fa-css-prefix}-vcard:before,
|
|
||||||
.@{fa-css-prefix}-address-card:before { content: @fa-var-address-card; }
|
|
||||||
.@{fa-css-prefix}-vcard-o:before,
|
|
||||||
.@{fa-css-prefix}-address-card-o:before { content: @fa-var-address-card-o; }
|
|
||||||
.@{fa-css-prefix}-user-circle:before { content: @fa-var-user-circle; }
|
|
||||||
.@{fa-css-prefix}-user-circle-o:before { content: @fa-var-user-circle-o; }
|
|
||||||
.@{fa-css-prefix}-user-o:before { content: @fa-var-user-o; }
|
|
||||||
.@{fa-css-prefix}-id-badge:before { content: @fa-var-id-badge; }
|
|
||||||
.@{fa-css-prefix}-drivers-license:before,
|
|
||||||
.@{fa-css-prefix}-id-card:before { content: @fa-var-id-card; }
|
|
||||||
.@{fa-css-prefix}-drivers-license-o:before,
|
|
||||||
.@{fa-css-prefix}-id-card-o:before { content: @fa-var-id-card-o; }
|
|
||||||
.@{fa-css-prefix}-quora:before { content: @fa-var-quora; }
|
|
||||||
.@{fa-css-prefix}-free-code-camp:before { content: @fa-var-free-code-camp; }
|
|
||||||
.@{fa-css-prefix}-telegram:before { content: @fa-var-telegram; }
|
|
||||||
.@{fa-css-prefix}-thermometer-4:before,
|
|
||||||
.@{fa-css-prefix}-thermometer:before,
|
|
||||||
.@{fa-css-prefix}-thermometer-full:before { content: @fa-var-thermometer-full; }
|
|
||||||
.@{fa-css-prefix}-thermometer-3:before,
|
|
||||||
.@{fa-css-prefix}-thermometer-three-quarters:before { content: @fa-var-thermometer-three-quarters; }
|
|
||||||
.@{fa-css-prefix}-thermometer-2:before,
|
|
||||||
.@{fa-css-prefix}-thermometer-half:before { content: @fa-var-thermometer-half; }
|
|
||||||
.@{fa-css-prefix}-thermometer-1:before,
|
|
||||||
.@{fa-css-prefix}-thermometer-quarter:before { content: @fa-var-thermometer-quarter; }
|
|
||||||
.@{fa-css-prefix}-thermometer-0:before,
|
|
||||||
.@{fa-css-prefix}-thermometer-empty:before { content: @fa-var-thermometer-empty; }
|
|
||||||
.@{fa-css-prefix}-shower:before { content: @fa-var-shower; }
|
|
||||||
.@{fa-css-prefix}-bathtub:before,
|
|
||||||
.@{fa-css-prefix}-s15:before,
|
|
||||||
.@{fa-css-prefix}-bath:before { content: @fa-var-bath; }
|
|
||||||
.@{fa-css-prefix}-podcast:before { content: @fa-var-podcast; }
|
|
||||||
.@{fa-css-prefix}-window-maximize:before { content: @fa-var-window-maximize; }
|
|
||||||
.@{fa-css-prefix}-window-minimize:before { content: @fa-var-window-minimize; }
|
|
||||||
.@{fa-css-prefix}-window-restore:before { content: @fa-var-window-restore; }
|
|
||||||
.@{fa-css-prefix}-times-rectangle:before,
|
|
||||||
.@{fa-css-prefix}-window-close:before { content: @fa-var-window-close; }
|
|
||||||
.@{fa-css-prefix}-times-rectangle-o:before,
|
|
||||||
.@{fa-css-prefix}-window-close-o:before { content: @fa-var-window-close-o; }
|
|
||||||
.@{fa-css-prefix}-bandcamp:before { content: @fa-var-bandcamp; }
|
|
||||||
.@{fa-css-prefix}-grav:before { content: @fa-var-grav; }
|
|
||||||
.@{fa-css-prefix}-etsy:before { content: @fa-var-etsy; }
|
|
||||||
.@{fa-css-prefix}-imdb:before { content: @fa-var-imdb; }
|
|
||||||
.@{fa-css-prefix}-ravelry:before { content: @fa-var-ravelry; }
|
|
||||||
.@{fa-css-prefix}-eercast:before { content: @fa-var-eercast; }
|
|
||||||
.@{fa-css-prefix}-microchip:before { content: @fa-var-microchip; }
|
|
||||||
.@{fa-css-prefix}-snowflake-o:before { content: @fa-var-snowflake-o; }
|
|
||||||
.@{fa-css-prefix}-superpowers:before { content: @fa-var-superpowers; }
|
|
||||||
.@{fa-css-prefix}-wpexplorer:before { content: @fa-var-wpexplorer; }
|
|
||||||
.@{fa-css-prefix}-meetup:before { content: @fa-var-meetup; }
|
|
||||||
|
|
|
@ -3,58 +3,23 @@
|
||||||
|
|
||||||
.fa-icon() {
|
.fa-icon() {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration
|
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-icon-rotate(@degrees, @rotation) {
|
.fa-icon-rotate(@degrees, @rotation) {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation})";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation);
|
||||||
-webkit-transform: rotate(@degrees);
|
-webkit-transform: rotate(@degrees);
|
||||||
-ms-transform: rotate(@degrees);
|
-ms-transform: rotate(@degrees);
|
||||||
transform: rotate(@degrees);
|
transform: rotate(@degrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-icon-flip(@horiz, @vert, @rotation) {
|
.fa-icon-flip(@horiz, @vert, @rotation) {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=@{rotation}, mirror=1)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1);
|
||||||
-webkit-transform: scale(@horiz, @vert);
|
-webkit-transform: scale(@horiz, @vert);
|
||||||
-ms-transform: scale(@horiz, @vert);
|
-ms-transform: scale(@horiz, @vert);
|
||||||
transform: scale(@horiz, @vert);
|
transform: scale(@horiz, @vert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Only display content to screen readers. A la Bootstrap 4.
|
|
||||||
//
|
|
||||||
// See: http://a11yproject.com/posts/how-to-hide-content/
|
|
||||||
|
|
||||||
.sr-only() {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0,0,0,0);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use in conjunction with .sr-only to only display content when it's focused.
|
|
||||||
//
|
|
||||||
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
|
|
||||||
//
|
|
||||||
// Credit: HTML5 Boilerplate
|
|
||||||
|
|
||||||
.sr-only-focusable() {
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
position: static;
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
margin: 0;
|
|
||||||
overflow: visible;
|
|
||||||
clip: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
font-family: 'FontAwesome';
|
font-family: 'FontAwesome';
|
||||||
src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
|
src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}');
|
||||||
src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
|
src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'),
|
||||||
url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'),
|
|
||||||
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
|
url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'),
|
||||||
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
|
url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'),
|
||||||
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
|
url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg');
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Screen Readers
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
.sr-only { .sr-only(); }
|
|
||||||
.sr-only-focusable { .sr-only-focusable(); }
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Animated Icons
|
// Spinning Icons
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
|
||||||
.@{fa-css-prefix}-spin {
|
.@{fa-css-prefix}-spin {
|
||||||
|
@ -6,11 +6,6 @@
|
||||||
animation: fa-spin 2s infinite linear;
|
animation: fa-spin 2s infinite linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{fa-css-prefix}-pulse {
|
|
||||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
|
||||||
animation: fa-spin 1s infinite steps(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes fa-spin {
|
@-webkit-keyframes fa-spin {
|
||||||
0% {
|
0% {
|
||||||
-webkit-transform: rotate(0deg);
|
-webkit-transform: rotate(0deg);
|
|
@ -2,29 +2,20 @@
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
|
||||||
@fa-font-path: "../fonts";
|
@fa-font-path: "../fonts";
|
||||||
@fa-font-size-base: 14px;
|
//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts"; // for referencing Bootstrap CDN font files directly
|
||||||
@fa-line-height-base: 1;
|
|
||||||
//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts"; // for referencing Bootstrap CDN font files directly
|
|
||||||
@fa-css-prefix: fa;
|
@fa-css-prefix: fa;
|
||||||
@fa-version: "4.7.0";
|
@fa-version: "4.2.0";
|
||||||
@fa-border-color: #eee;
|
@fa-border-color: #eee;
|
||||||
@fa-inverse: #fff;
|
@fa-inverse: #fff;
|
||||||
@fa-li-width: (30em / 14);
|
@fa-li-width: (30em / 14);
|
||||||
|
|
||||||
@fa-var-500px: "\f26e";
|
|
||||||
@fa-var-address-book: "\f2b9";
|
|
||||||
@fa-var-address-book-o: "\f2ba";
|
|
||||||
@fa-var-address-card: "\f2bb";
|
|
||||||
@fa-var-address-card-o: "\f2bc";
|
|
||||||
@fa-var-adjust: "\f042";
|
@fa-var-adjust: "\f042";
|
||||||
@fa-var-adn: "\f170";
|
@fa-var-adn: "\f170";
|
||||||
@fa-var-align-center: "\f037";
|
@fa-var-align-center: "\f037";
|
||||||
@fa-var-align-justify: "\f039";
|
@fa-var-align-justify: "\f039";
|
||||||
@fa-var-align-left: "\f036";
|
@fa-var-align-left: "\f036";
|
||||||
@fa-var-align-right: "\f038";
|
@fa-var-align-right: "\f038";
|
||||||
@fa-var-amazon: "\f270";
|
|
||||||
@fa-var-ambulance: "\f0f9";
|
@fa-var-ambulance: "\f0f9";
|
||||||
@fa-var-american-sign-language-interpreting: "\f2a3";
|
|
||||||
@fa-var-anchor: "\f13d";
|
@fa-var-anchor: "\f13d";
|
||||||
@fa-var-android: "\f17b";
|
@fa-var-android: "\f17b";
|
||||||
@fa-var-angellist: "\f209";
|
@fa-var-angellist: "\f209";
|
||||||
|
@ -55,35 +46,16 @@
|
||||||
@fa-var-arrows-alt: "\f0b2";
|
@fa-var-arrows-alt: "\f0b2";
|
||||||
@fa-var-arrows-h: "\f07e";
|
@fa-var-arrows-h: "\f07e";
|
||||||
@fa-var-arrows-v: "\f07d";
|
@fa-var-arrows-v: "\f07d";
|
||||||
@fa-var-asl-interpreting: "\f2a3";
|
|
||||||
@fa-var-assistive-listening-systems: "\f2a2";
|
|
||||||
@fa-var-asterisk: "\f069";
|
@fa-var-asterisk: "\f069";
|
||||||
@fa-var-at: "\f1fa";
|
@fa-var-at: "\f1fa";
|
||||||
@fa-var-audio-description: "\f29e";
|
|
||||||
@fa-var-automobile: "\f1b9";
|
@fa-var-automobile: "\f1b9";
|
||||||
@fa-var-backward: "\f04a";
|
@fa-var-backward: "\f04a";
|
||||||
@fa-var-balance-scale: "\f24e";
|
|
||||||
@fa-var-ban: "\f05e";
|
@fa-var-ban: "\f05e";
|
||||||
@fa-var-bandcamp: "\f2d5";
|
|
||||||
@fa-var-bank: "\f19c";
|
@fa-var-bank: "\f19c";
|
||||||
@fa-var-bar-chart: "\f080";
|
@fa-var-bar-chart: "\f080";
|
||||||
@fa-var-bar-chart-o: "\f080";
|
@fa-var-bar-chart-o: "\f080";
|
||||||
@fa-var-barcode: "\f02a";
|
@fa-var-barcode: "\f02a";
|
||||||
@fa-var-bars: "\f0c9";
|
@fa-var-bars: "\f0c9";
|
||||||
@fa-var-bath: "\f2cd";
|
|
||||||
@fa-var-bathtub: "\f2cd";
|
|
||||||
@fa-var-battery: "\f240";
|
|
||||||
@fa-var-battery-0: "\f244";
|
|
||||||
@fa-var-battery-1: "\f243";
|
|
||||||
@fa-var-battery-2: "\f242";
|
|
||||||
@fa-var-battery-3: "\f241";
|
|
||||||
@fa-var-battery-4: "\f240";
|
|
||||||
@fa-var-battery-empty: "\f244";
|
|
||||||
@fa-var-battery-full: "\f240";
|
|
||||||
@fa-var-battery-half: "\f242";
|
|
||||||
@fa-var-battery-quarter: "\f243";
|
|
||||||
@fa-var-battery-three-quarters: "\f241";
|
|
||||||
@fa-var-bed: "\f236";
|
|
||||||
@fa-var-beer: "\f0fc";
|
@fa-var-beer: "\f0fc";
|
||||||
@fa-var-behance: "\f1b4";
|
@fa-var-behance: "\f1b4";
|
||||||
@fa-var-behance-square: "\f1b5";
|
@fa-var-behance-square: "\f1b5";
|
||||||
|
@ -97,17 +69,12 @@
|
||||||
@fa-var-bitbucket: "\f171";
|
@fa-var-bitbucket: "\f171";
|
||||||
@fa-var-bitbucket-square: "\f172";
|
@fa-var-bitbucket-square: "\f172";
|
||||||
@fa-var-bitcoin: "\f15a";
|
@fa-var-bitcoin: "\f15a";
|
||||||
@fa-var-black-tie: "\f27e";
|
|
||||||
@fa-var-blind: "\f29d";
|
|
||||||
@fa-var-bluetooth: "\f293";
|
|
||||||
@fa-var-bluetooth-b: "\f294";
|
|
||||||
@fa-var-bold: "\f032";
|
@fa-var-bold: "\f032";
|
||||||
@fa-var-bolt: "\f0e7";
|
@fa-var-bolt: "\f0e7";
|
||||||
@fa-var-bomb: "\f1e2";
|
@fa-var-bomb: "\f1e2";
|
||||||
@fa-var-book: "\f02d";
|
@fa-var-book: "\f02d";
|
||||||
@fa-var-bookmark: "\f02e";
|
@fa-var-bookmark: "\f02e";
|
||||||
@fa-var-bookmark-o: "\f097";
|
@fa-var-bookmark-o: "\f097";
|
||||||
@fa-var-braille: "\f2a1";
|
|
||||||
@fa-var-briefcase: "\f0b1";
|
@fa-var-briefcase: "\f0b1";
|
||||||
@fa-var-btc: "\f15a";
|
@fa-var-btc: "\f15a";
|
||||||
@fa-var-bug: "\f188";
|
@fa-var-bug: "\f188";
|
||||||
|
@ -116,15 +83,10 @@
|
||||||
@fa-var-bullhorn: "\f0a1";
|
@fa-var-bullhorn: "\f0a1";
|
||||||
@fa-var-bullseye: "\f140";
|
@fa-var-bullseye: "\f140";
|
||||||
@fa-var-bus: "\f207";
|
@fa-var-bus: "\f207";
|
||||||
@fa-var-buysellads: "\f20d";
|
|
||||||
@fa-var-cab: "\f1ba";
|
@fa-var-cab: "\f1ba";
|
||||||
@fa-var-calculator: "\f1ec";
|
@fa-var-calculator: "\f1ec";
|
||||||
@fa-var-calendar: "\f073";
|
@fa-var-calendar: "\f073";
|
||||||
@fa-var-calendar-check-o: "\f274";
|
|
||||||
@fa-var-calendar-minus-o: "\f272";
|
|
||||||
@fa-var-calendar-o: "\f133";
|
@fa-var-calendar-o: "\f133";
|
||||||
@fa-var-calendar-plus-o: "\f271";
|
|
||||||
@fa-var-calendar-times-o: "\f273";
|
|
||||||
@fa-var-camera: "\f030";
|
@fa-var-camera: "\f030";
|
||||||
@fa-var-camera-retro: "\f083";
|
@fa-var-camera-retro: "\f083";
|
||||||
@fa-var-car: "\f1b9";
|
@fa-var-car: "\f1b9";
|
||||||
|
@ -136,13 +98,9 @@
|
||||||
@fa-var-caret-square-o-right: "\f152";
|
@fa-var-caret-square-o-right: "\f152";
|
||||||
@fa-var-caret-square-o-up: "\f151";
|
@fa-var-caret-square-o-up: "\f151";
|
||||||
@fa-var-caret-up: "\f0d8";
|
@fa-var-caret-up: "\f0d8";
|
||||||
@fa-var-cart-arrow-down: "\f218";
|
|
||||||
@fa-var-cart-plus: "\f217";
|
|
||||||
@fa-var-cc: "\f20a";
|
@fa-var-cc: "\f20a";
|
||||||
@fa-var-cc-amex: "\f1f3";
|
@fa-var-cc-amex: "\f1f3";
|
||||||
@fa-var-cc-diners-club: "\f24c";
|
|
||||||
@fa-var-cc-discover: "\f1f2";
|
@fa-var-cc-discover: "\f1f2";
|
||||||
@fa-var-cc-jcb: "\f24b";
|
|
||||||
@fa-var-cc-mastercard: "\f1f1";
|
@fa-var-cc-mastercard: "\f1f1";
|
||||||
@fa-var-cc-paypal: "\f1f4";
|
@fa-var-cc-paypal: "\f1f4";
|
||||||
@fa-var-cc-stripe: "\f1f5";
|
@fa-var-cc-stripe: "\f1f5";
|
||||||
|
@ -164,14 +122,12 @@
|
||||||
@fa-var-chevron-right: "\f054";
|
@fa-var-chevron-right: "\f054";
|
||||||
@fa-var-chevron-up: "\f077";
|
@fa-var-chevron-up: "\f077";
|
||||||
@fa-var-child: "\f1ae";
|
@fa-var-child: "\f1ae";
|
||||||
@fa-var-chrome: "\f268";
|
|
||||||
@fa-var-circle: "\f111";
|
@fa-var-circle: "\f111";
|
||||||
@fa-var-circle-o: "\f10c";
|
@fa-var-circle-o: "\f10c";
|
||||||
@fa-var-circle-o-notch: "\f1ce";
|
@fa-var-circle-o-notch: "\f1ce";
|
||||||
@fa-var-circle-thin: "\f1db";
|
@fa-var-circle-thin: "\f1db";
|
||||||
@fa-var-clipboard: "\f0ea";
|
@fa-var-clipboard: "\f0ea";
|
||||||
@fa-var-clock-o: "\f017";
|
@fa-var-clock-o: "\f017";
|
||||||
@fa-var-clone: "\f24d";
|
|
||||||
@fa-var-close: "\f00d";
|
@fa-var-close: "\f00d";
|
||||||
@fa-var-cloud: "\f0c2";
|
@fa-var-cloud: "\f0c2";
|
||||||
@fa-var-cloud-download: "\f0ed";
|
@fa-var-cloud-download: "\f0ed";
|
||||||
|
@ -180,26 +136,19 @@
|
||||||
@fa-var-code: "\f121";
|
@fa-var-code: "\f121";
|
||||||
@fa-var-code-fork: "\f126";
|
@fa-var-code-fork: "\f126";
|
||||||
@fa-var-codepen: "\f1cb";
|
@fa-var-codepen: "\f1cb";
|
||||||
@fa-var-codiepie: "\f284";
|
|
||||||
@fa-var-coffee: "\f0f4";
|
@fa-var-coffee: "\f0f4";
|
||||||
@fa-var-cog: "\f013";
|
@fa-var-cog: "\f013";
|
||||||
@fa-var-cogs: "\f085";
|
@fa-var-cogs: "\f085";
|
||||||
@fa-var-columns: "\f0db";
|
@fa-var-columns: "\f0db";
|
||||||
@fa-var-comment: "\f075";
|
@fa-var-comment: "\f075";
|
||||||
@fa-var-comment-o: "\f0e5";
|
@fa-var-comment-o: "\f0e5";
|
||||||
@fa-var-commenting: "\f27a";
|
|
||||||
@fa-var-commenting-o: "\f27b";
|
|
||||||
@fa-var-comments: "\f086";
|
@fa-var-comments: "\f086";
|
||||||
@fa-var-comments-o: "\f0e6";
|
@fa-var-comments-o: "\f0e6";
|
||||||
@fa-var-compass: "\f14e";
|
@fa-var-compass: "\f14e";
|
||||||
@fa-var-compress: "\f066";
|
@fa-var-compress: "\f066";
|
||||||
@fa-var-connectdevelop: "\f20e";
|
|
||||||
@fa-var-contao: "\f26d";
|
|
||||||
@fa-var-copy: "\f0c5";
|
@fa-var-copy: "\f0c5";
|
||||||
@fa-var-copyright: "\f1f9";
|
@fa-var-copyright: "\f1f9";
|
||||||
@fa-var-creative-commons: "\f25e";
|
|
||||||
@fa-var-credit-card: "\f09d";
|
@fa-var-credit-card: "\f09d";
|
||||||
@fa-var-credit-card-alt: "\f283";
|
|
||||||
@fa-var-crop: "\f125";
|
@fa-var-crop: "\f125";
|
||||||
@fa-var-crosshairs: "\f05b";
|
@fa-var-crosshairs: "\f05b";
|
||||||
@fa-var-css3: "\f13c";
|
@fa-var-css3: "\f13c";
|
||||||
|
@ -208,39 +157,27 @@
|
||||||
@fa-var-cut: "\f0c4";
|
@fa-var-cut: "\f0c4";
|
||||||
@fa-var-cutlery: "\f0f5";
|
@fa-var-cutlery: "\f0f5";
|
||||||
@fa-var-dashboard: "\f0e4";
|
@fa-var-dashboard: "\f0e4";
|
||||||
@fa-var-dashcube: "\f210";
|
|
||||||
@fa-var-database: "\f1c0";
|
@fa-var-database: "\f1c0";
|
||||||
@fa-var-deaf: "\f2a4";
|
|
||||||
@fa-var-deafness: "\f2a4";
|
|
||||||
@fa-var-dedent: "\f03b";
|
@fa-var-dedent: "\f03b";
|
||||||
@fa-var-delicious: "\f1a5";
|
@fa-var-delicious: "\f1a5";
|
||||||
@fa-var-desktop: "\f108";
|
@fa-var-desktop: "\f108";
|
||||||
@fa-var-deviantart: "\f1bd";
|
@fa-var-deviantart: "\f1bd";
|
||||||
@fa-var-diamond: "\f219";
|
|
||||||
@fa-var-digg: "\f1a6";
|
@fa-var-digg: "\f1a6";
|
||||||
@fa-var-dollar: "\f155";
|
@fa-var-dollar: "\f155";
|
||||||
@fa-var-dot-circle-o: "\f192";
|
@fa-var-dot-circle-o: "\f192";
|
||||||
@fa-var-download: "\f019";
|
@fa-var-download: "\f019";
|
||||||
@fa-var-dribbble: "\f17d";
|
@fa-var-dribbble: "\f17d";
|
||||||
@fa-var-drivers-license: "\f2c2";
|
|
||||||
@fa-var-drivers-license-o: "\f2c3";
|
|
||||||
@fa-var-dropbox: "\f16b";
|
@fa-var-dropbox: "\f16b";
|
||||||
@fa-var-drupal: "\f1a9";
|
@fa-var-drupal: "\f1a9";
|
||||||
@fa-var-edge: "\f282";
|
|
||||||
@fa-var-edit: "\f044";
|
@fa-var-edit: "\f044";
|
||||||
@fa-var-eercast: "\f2da";
|
|
||||||
@fa-var-eject: "\f052";
|
@fa-var-eject: "\f052";
|
||||||
@fa-var-ellipsis-h: "\f141";
|
@fa-var-ellipsis-h: "\f141";
|
||||||
@fa-var-ellipsis-v: "\f142";
|
@fa-var-ellipsis-v: "\f142";
|
||||||
@fa-var-empire: "\f1d1";
|
@fa-var-empire: "\f1d1";
|
||||||
@fa-var-envelope: "\f0e0";
|
@fa-var-envelope: "\f0e0";
|
||||||
@fa-var-envelope-o: "\f003";
|
@fa-var-envelope-o: "\f003";
|
||||||
@fa-var-envelope-open: "\f2b6";
|
|
||||||
@fa-var-envelope-open-o: "\f2b7";
|
|
||||||
@fa-var-envelope-square: "\f199";
|
@fa-var-envelope-square: "\f199";
|
||||||
@fa-var-envira: "\f299";
|
|
||||||
@fa-var-eraser: "\f12d";
|
@fa-var-eraser: "\f12d";
|
||||||
@fa-var-etsy: "\f2d7";
|
|
||||||
@fa-var-eur: "\f153";
|
@fa-var-eur: "\f153";
|
||||||
@fa-var-euro: "\f153";
|
@fa-var-euro: "\f153";
|
||||||
@fa-var-exchange: "\f0ec";
|
@fa-var-exchange: "\f0ec";
|
||||||
|
@ -248,21 +185,16 @@
|
||||||
@fa-var-exclamation-circle: "\f06a";
|
@fa-var-exclamation-circle: "\f06a";
|
||||||
@fa-var-exclamation-triangle: "\f071";
|
@fa-var-exclamation-triangle: "\f071";
|
||||||
@fa-var-expand: "\f065";
|
@fa-var-expand: "\f065";
|
||||||
@fa-var-expeditedssl: "\f23e";
|
|
||||||
@fa-var-external-link: "\f08e";
|
@fa-var-external-link: "\f08e";
|
||||||
@fa-var-external-link-square: "\f14c";
|
@fa-var-external-link-square: "\f14c";
|
||||||
@fa-var-eye: "\f06e";
|
@fa-var-eye: "\f06e";
|
||||||
@fa-var-eye-slash: "\f070";
|
@fa-var-eye-slash: "\f070";
|
||||||
@fa-var-eyedropper: "\f1fb";
|
@fa-var-eyedropper: "\f1fb";
|
||||||
@fa-var-fa: "\f2b4";
|
|
||||||
@fa-var-facebook: "\f09a";
|
@fa-var-facebook: "\f09a";
|
||||||
@fa-var-facebook-f: "\f09a";
|
|
||||||
@fa-var-facebook-official: "\f230";
|
|
||||||
@fa-var-facebook-square: "\f082";
|
@fa-var-facebook-square: "\f082";
|
||||||
@fa-var-fast-backward: "\f049";
|
@fa-var-fast-backward: "\f049";
|
||||||
@fa-var-fast-forward: "\f050";
|
@fa-var-fast-forward: "\f050";
|
||||||
@fa-var-fax: "\f1ac";
|
@fa-var-fax: "\f1ac";
|
||||||
@fa-var-feed: "\f09e";
|
|
||||||
@fa-var-female: "\f182";
|
@fa-var-female: "\f182";
|
||||||
@fa-var-fighter-jet: "\f0fb";
|
@fa-var-fighter-jet: "\f0fb";
|
||||||
@fa-var-file: "\f15b";
|
@fa-var-file: "\f15b";
|
||||||
|
@ -288,8 +220,6 @@
|
||||||
@fa-var-filter: "\f0b0";
|
@fa-var-filter: "\f0b0";
|
||||||
@fa-var-fire: "\f06d";
|
@fa-var-fire: "\f06d";
|
||||||
@fa-var-fire-extinguisher: "\f134";
|
@fa-var-fire-extinguisher: "\f134";
|
||||||
@fa-var-firefox: "\f269";
|
|
||||||
@fa-var-first-order: "\f2b0";
|
|
||||||
@fa-var-flag: "\f024";
|
@fa-var-flag: "\f024";
|
||||||
@fa-var-flag-checkered: "\f11e";
|
@fa-var-flag-checkered: "\f11e";
|
||||||
@fa-var-flag-o: "\f11d";
|
@fa-var-flag-o: "\f11d";
|
||||||
|
@ -302,13 +232,8 @@
|
||||||
@fa-var-folder-open: "\f07c";
|
@fa-var-folder-open: "\f07c";
|
||||||
@fa-var-folder-open-o: "\f115";
|
@fa-var-folder-open-o: "\f115";
|
||||||
@fa-var-font: "\f031";
|
@fa-var-font: "\f031";
|
||||||
@fa-var-font-awesome: "\f2b4";
|
|
||||||
@fa-var-fonticons: "\f280";
|
|
||||||
@fa-var-fort-awesome: "\f286";
|
|
||||||
@fa-var-forumbee: "\f211";
|
|
||||||
@fa-var-forward: "\f04e";
|
@fa-var-forward: "\f04e";
|
||||||
@fa-var-foursquare: "\f180";
|
@fa-var-foursquare: "\f180";
|
||||||
@fa-var-free-code-camp: "\f2c5";
|
|
||||||
@fa-var-frown-o: "\f119";
|
@fa-var-frown-o: "\f119";
|
||||||
@fa-var-futbol-o: "\f1e3";
|
@fa-var-futbol-o: "\f1e3";
|
||||||
@fa-var-gamepad: "\f11b";
|
@fa-var-gamepad: "\f11b";
|
||||||
|
@ -317,87 +242,45 @@
|
||||||
@fa-var-ge: "\f1d1";
|
@fa-var-ge: "\f1d1";
|
||||||
@fa-var-gear: "\f013";
|
@fa-var-gear: "\f013";
|
||||||
@fa-var-gears: "\f085";
|
@fa-var-gears: "\f085";
|
||||||
@fa-var-genderless: "\f22d";
|
|
||||||
@fa-var-get-pocket: "\f265";
|
|
||||||
@fa-var-gg: "\f260";
|
|
||||||
@fa-var-gg-circle: "\f261";
|
|
||||||
@fa-var-gift: "\f06b";
|
@fa-var-gift: "\f06b";
|
||||||
@fa-var-git: "\f1d3";
|
@fa-var-git: "\f1d3";
|
||||||
@fa-var-git-square: "\f1d2";
|
@fa-var-git-square: "\f1d2";
|
||||||
@fa-var-github: "\f09b";
|
@fa-var-github: "\f09b";
|
||||||
@fa-var-github-alt: "\f113";
|
@fa-var-github-alt: "\f113";
|
||||||
@fa-var-github-square: "\f092";
|
@fa-var-github-square: "\f092";
|
||||||
@fa-var-gitlab: "\f296";
|
|
||||||
@fa-var-gittip: "\f184";
|
@fa-var-gittip: "\f184";
|
||||||
@fa-var-glass: "\f000";
|
@fa-var-glass: "\f000";
|
||||||
@fa-var-glide: "\f2a5";
|
|
||||||
@fa-var-glide-g: "\f2a6";
|
|
||||||
@fa-var-globe: "\f0ac";
|
@fa-var-globe: "\f0ac";
|
||||||
@fa-var-google: "\f1a0";
|
@fa-var-google: "\f1a0";
|
||||||
@fa-var-google-plus: "\f0d5";
|
@fa-var-google-plus: "\f0d5";
|
||||||
@fa-var-google-plus-circle: "\f2b3";
|
|
||||||
@fa-var-google-plus-official: "\f2b3";
|
|
||||||
@fa-var-google-plus-square: "\f0d4";
|
@fa-var-google-plus-square: "\f0d4";
|
||||||
@fa-var-google-wallet: "\f1ee";
|
@fa-var-google-wallet: "\f1ee";
|
||||||
@fa-var-graduation-cap: "\f19d";
|
@fa-var-graduation-cap: "\f19d";
|
||||||
@fa-var-gratipay: "\f184";
|
|
||||||
@fa-var-grav: "\f2d6";
|
|
||||||
@fa-var-group: "\f0c0";
|
@fa-var-group: "\f0c0";
|
||||||
@fa-var-h-square: "\f0fd";
|
@fa-var-h-square: "\f0fd";
|
||||||
@fa-var-hacker-news: "\f1d4";
|
@fa-var-hacker-news: "\f1d4";
|
||||||
@fa-var-hand-grab-o: "\f255";
|
|
||||||
@fa-var-hand-lizard-o: "\f258";
|
|
||||||
@fa-var-hand-o-down: "\f0a7";
|
@fa-var-hand-o-down: "\f0a7";
|
||||||
@fa-var-hand-o-left: "\f0a5";
|
@fa-var-hand-o-left: "\f0a5";
|
||||||
@fa-var-hand-o-right: "\f0a4";
|
@fa-var-hand-o-right: "\f0a4";
|
||||||
@fa-var-hand-o-up: "\f0a6";
|
@fa-var-hand-o-up: "\f0a6";
|
||||||
@fa-var-hand-paper-o: "\f256";
|
|
||||||
@fa-var-hand-peace-o: "\f25b";
|
|
||||||
@fa-var-hand-pointer-o: "\f25a";
|
|
||||||
@fa-var-hand-rock-o: "\f255";
|
|
||||||
@fa-var-hand-scissors-o: "\f257";
|
|
||||||
@fa-var-hand-spock-o: "\f259";
|
|
||||||
@fa-var-hand-stop-o: "\f256";
|
|
||||||
@fa-var-handshake-o: "\f2b5";
|
|
||||||
@fa-var-hard-of-hearing: "\f2a4";
|
|
||||||
@fa-var-hashtag: "\f292";
|
|
||||||
@fa-var-hdd-o: "\f0a0";
|
@fa-var-hdd-o: "\f0a0";
|
||||||
@fa-var-header: "\f1dc";
|
@fa-var-header: "\f1dc";
|
||||||
@fa-var-headphones: "\f025";
|
@fa-var-headphones: "\f025";
|
||||||
@fa-var-heart: "\f004";
|
@fa-var-heart: "\f004";
|
||||||
@fa-var-heart-o: "\f08a";
|
@fa-var-heart-o: "\f08a";
|
||||||
@fa-var-heartbeat: "\f21e";
|
|
||||||
@fa-var-history: "\f1da";
|
@fa-var-history: "\f1da";
|
||||||
@fa-var-home: "\f015";
|
@fa-var-home: "\f015";
|
||||||
@fa-var-hospital-o: "\f0f8";
|
@fa-var-hospital-o: "\f0f8";
|
||||||
@fa-var-hotel: "\f236";
|
|
||||||
@fa-var-hourglass: "\f254";
|
|
||||||
@fa-var-hourglass-1: "\f251";
|
|
||||||
@fa-var-hourglass-2: "\f252";
|
|
||||||
@fa-var-hourglass-3: "\f253";
|
|
||||||
@fa-var-hourglass-end: "\f253";
|
|
||||||
@fa-var-hourglass-half: "\f252";
|
|
||||||
@fa-var-hourglass-o: "\f250";
|
|
||||||
@fa-var-hourglass-start: "\f251";
|
|
||||||
@fa-var-houzz: "\f27c";
|
|
||||||
@fa-var-html5: "\f13b";
|
@fa-var-html5: "\f13b";
|
||||||
@fa-var-i-cursor: "\f246";
|
|
||||||
@fa-var-id-badge: "\f2c1";
|
|
||||||
@fa-var-id-card: "\f2c2";
|
|
||||||
@fa-var-id-card-o: "\f2c3";
|
|
||||||
@fa-var-ils: "\f20b";
|
@fa-var-ils: "\f20b";
|
||||||
@fa-var-image: "\f03e";
|
@fa-var-image: "\f03e";
|
||||||
@fa-var-imdb: "\f2d8";
|
|
||||||
@fa-var-inbox: "\f01c";
|
@fa-var-inbox: "\f01c";
|
||||||
@fa-var-indent: "\f03c";
|
@fa-var-indent: "\f03c";
|
||||||
@fa-var-industry: "\f275";
|
|
||||||
@fa-var-info: "\f129";
|
@fa-var-info: "\f129";
|
||||||
@fa-var-info-circle: "\f05a";
|
@fa-var-info-circle: "\f05a";
|
||||||
@fa-var-inr: "\f156";
|
@fa-var-inr: "\f156";
|
||||||
@fa-var-instagram: "\f16d";
|
@fa-var-instagram: "\f16d";
|
||||||
@fa-var-institution: "\f19c";
|
@fa-var-institution: "\f19c";
|
||||||
@fa-var-internet-explorer: "\f26b";
|
|
||||||
@fa-var-intersex: "\f224";
|
|
||||||
@fa-var-ioxhost: "\f208";
|
@fa-var-ioxhost: "\f208";
|
||||||
@fa-var-italic: "\f033";
|
@fa-var-italic: "\f033";
|
||||||
@fa-var-joomla: "\f1aa";
|
@fa-var-joomla: "\f1aa";
|
||||||
|
@ -411,7 +294,6 @@
|
||||||
@fa-var-lastfm: "\f202";
|
@fa-var-lastfm: "\f202";
|
||||||
@fa-var-lastfm-square: "\f203";
|
@fa-var-lastfm-square: "\f203";
|
||||||
@fa-var-leaf: "\f06c";
|
@fa-var-leaf: "\f06c";
|
||||||
@fa-var-leanpub: "\f212";
|
|
||||||
@fa-var-legal: "\f0e3";
|
@fa-var-legal: "\f0e3";
|
||||||
@fa-var-lemon-o: "\f094";
|
@fa-var-lemon-o: "\f094";
|
||||||
@fa-var-level-down: "\f149";
|
@fa-var-level-down: "\f149";
|
||||||
|
@ -425,7 +307,6 @@
|
||||||
@fa-var-link: "\f0c1";
|
@fa-var-link: "\f0c1";
|
||||||
@fa-var-linkedin: "\f0e1";
|
@fa-var-linkedin: "\f0e1";
|
||||||
@fa-var-linkedin-square: "\f08c";
|
@fa-var-linkedin-square: "\f08c";
|
||||||
@fa-var-linode: "\f2b8";
|
|
||||||
@fa-var-linux: "\f17c";
|
@fa-var-linux: "\f17c";
|
||||||
@fa-var-list: "\f03a";
|
@fa-var-list: "\f03a";
|
||||||
@fa-var-list-alt: "\f022";
|
@fa-var-list-alt: "\f022";
|
||||||
|
@ -437,58 +318,32 @@
|
||||||
@fa-var-long-arrow-left: "\f177";
|
@fa-var-long-arrow-left: "\f177";
|
||||||
@fa-var-long-arrow-right: "\f178";
|
@fa-var-long-arrow-right: "\f178";
|
||||||
@fa-var-long-arrow-up: "\f176";
|
@fa-var-long-arrow-up: "\f176";
|
||||||
@fa-var-low-vision: "\f2a8";
|
|
||||||
@fa-var-magic: "\f0d0";
|
@fa-var-magic: "\f0d0";
|
||||||
@fa-var-magnet: "\f076";
|
@fa-var-magnet: "\f076";
|
||||||
@fa-var-mail-forward: "\f064";
|
@fa-var-mail-forward: "\f064";
|
||||||
@fa-var-mail-reply: "\f112";
|
@fa-var-mail-reply: "\f112";
|
||||||
@fa-var-mail-reply-all: "\f122";
|
@fa-var-mail-reply-all: "\f122";
|
||||||
@fa-var-male: "\f183";
|
@fa-var-male: "\f183";
|
||||||
@fa-var-map: "\f279";
|
|
||||||
@fa-var-map-marker: "\f041";
|
@fa-var-map-marker: "\f041";
|
||||||
@fa-var-map-o: "\f278";
|
|
||||||
@fa-var-map-pin: "\f276";
|
|
||||||
@fa-var-map-signs: "\f277";
|
|
||||||
@fa-var-mars: "\f222";
|
|
||||||
@fa-var-mars-double: "\f227";
|
|
||||||
@fa-var-mars-stroke: "\f229";
|
|
||||||
@fa-var-mars-stroke-h: "\f22b";
|
|
||||||
@fa-var-mars-stroke-v: "\f22a";
|
|
||||||
@fa-var-maxcdn: "\f136";
|
@fa-var-maxcdn: "\f136";
|
||||||
@fa-var-meanpath: "\f20c";
|
@fa-var-meanpath: "\f20c";
|
||||||
@fa-var-medium: "\f23a";
|
|
||||||
@fa-var-medkit: "\f0fa";
|
@fa-var-medkit: "\f0fa";
|
||||||
@fa-var-meetup: "\f2e0";
|
|
||||||
@fa-var-meh-o: "\f11a";
|
@fa-var-meh-o: "\f11a";
|
||||||
@fa-var-mercury: "\f223";
|
|
||||||
@fa-var-microchip: "\f2db";
|
|
||||||
@fa-var-microphone: "\f130";
|
@fa-var-microphone: "\f130";
|
||||||
@fa-var-microphone-slash: "\f131";
|
@fa-var-microphone-slash: "\f131";
|
||||||
@fa-var-minus: "\f068";
|
@fa-var-minus: "\f068";
|
||||||
@fa-var-minus-circle: "\f056";
|
@fa-var-minus-circle: "\f056";
|
||||||
@fa-var-minus-square: "\f146";
|
@fa-var-minus-square: "\f146";
|
||||||
@fa-var-minus-square-o: "\f147";
|
@fa-var-minus-square-o: "\f147";
|
||||||
@fa-var-mixcloud: "\f289";
|
|
||||||
@fa-var-mobile: "\f10b";
|
@fa-var-mobile: "\f10b";
|
||||||
@fa-var-mobile-phone: "\f10b";
|
@fa-var-mobile-phone: "\f10b";
|
||||||
@fa-var-modx: "\f285";
|
|
||||||
@fa-var-money: "\f0d6";
|
@fa-var-money: "\f0d6";
|
||||||
@fa-var-moon-o: "\f186";
|
@fa-var-moon-o: "\f186";
|
||||||
@fa-var-mortar-board: "\f19d";
|
@fa-var-mortar-board: "\f19d";
|
||||||
@fa-var-motorcycle: "\f21c";
|
|
||||||
@fa-var-mouse-pointer: "\f245";
|
|
||||||
@fa-var-music: "\f001";
|
@fa-var-music: "\f001";
|
||||||
@fa-var-navicon: "\f0c9";
|
@fa-var-navicon: "\f0c9";
|
||||||
@fa-var-neuter: "\f22c";
|
|
||||||
@fa-var-newspaper-o: "\f1ea";
|
@fa-var-newspaper-o: "\f1ea";
|
||||||
@fa-var-object-group: "\f247";
|
|
||||||
@fa-var-object-ungroup: "\f248";
|
|
||||||
@fa-var-odnoklassniki: "\f263";
|
|
||||||
@fa-var-odnoklassniki-square: "\f264";
|
|
||||||
@fa-var-opencart: "\f23d";
|
|
||||||
@fa-var-openid: "\f19b";
|
@fa-var-openid: "\f19b";
|
||||||
@fa-var-opera: "\f26a";
|
|
||||||
@fa-var-optin-monster: "\f23c";
|
|
||||||
@fa-var-outdent: "\f03b";
|
@fa-var-outdent: "\f03b";
|
||||||
@fa-var-pagelines: "\f18c";
|
@fa-var-pagelines: "\f18c";
|
||||||
@fa-var-paint-brush: "\f1fc";
|
@fa-var-paint-brush: "\f1fc";
|
||||||
|
@ -498,24 +353,19 @@
|
||||||
@fa-var-paragraph: "\f1dd";
|
@fa-var-paragraph: "\f1dd";
|
||||||
@fa-var-paste: "\f0ea";
|
@fa-var-paste: "\f0ea";
|
||||||
@fa-var-pause: "\f04c";
|
@fa-var-pause: "\f04c";
|
||||||
@fa-var-pause-circle: "\f28b";
|
|
||||||
@fa-var-pause-circle-o: "\f28c";
|
|
||||||
@fa-var-paw: "\f1b0";
|
@fa-var-paw: "\f1b0";
|
||||||
@fa-var-paypal: "\f1ed";
|
@fa-var-paypal: "\f1ed";
|
||||||
@fa-var-pencil: "\f040";
|
@fa-var-pencil: "\f040";
|
||||||
@fa-var-pencil-square: "\f14b";
|
@fa-var-pencil-square: "\f14b";
|
||||||
@fa-var-pencil-square-o: "\f044";
|
@fa-var-pencil-square-o: "\f044";
|
||||||
@fa-var-percent: "\f295";
|
|
||||||
@fa-var-phone: "\f095";
|
@fa-var-phone: "\f095";
|
||||||
@fa-var-phone-square: "\f098";
|
@fa-var-phone-square: "\f098";
|
||||||
@fa-var-photo: "\f03e";
|
@fa-var-photo: "\f03e";
|
||||||
@fa-var-picture-o: "\f03e";
|
@fa-var-picture-o: "\f03e";
|
||||||
@fa-var-pie-chart: "\f200";
|
@fa-var-pie-chart: "\f200";
|
||||||
@fa-var-pied-piper: "\f2ae";
|
@fa-var-pied-piper: "\f1a7";
|
||||||
@fa-var-pied-piper-alt: "\f1a8";
|
@fa-var-pied-piper-alt: "\f1a8";
|
||||||
@fa-var-pied-piper-pp: "\f1a7";
|
|
||||||
@fa-var-pinterest: "\f0d2";
|
@fa-var-pinterest: "\f0d2";
|
||||||
@fa-var-pinterest-p: "\f231";
|
|
||||||
@fa-var-pinterest-square: "\f0d3";
|
@fa-var-pinterest-square: "\f0d3";
|
||||||
@fa-var-plane: "\f072";
|
@fa-var-plane: "\f072";
|
||||||
@fa-var-play: "\f04b";
|
@fa-var-play: "\f04b";
|
||||||
|
@ -526,36 +376,28 @@
|
||||||
@fa-var-plus-circle: "\f055";
|
@fa-var-plus-circle: "\f055";
|
||||||
@fa-var-plus-square: "\f0fe";
|
@fa-var-plus-square: "\f0fe";
|
||||||
@fa-var-plus-square-o: "\f196";
|
@fa-var-plus-square-o: "\f196";
|
||||||
@fa-var-podcast: "\f2ce";
|
|
||||||
@fa-var-power-off: "\f011";
|
@fa-var-power-off: "\f011";
|
||||||
@fa-var-print: "\f02f";
|
@fa-var-print: "\f02f";
|
||||||
@fa-var-product-hunt: "\f288";
|
|
||||||
@fa-var-puzzle-piece: "\f12e";
|
@fa-var-puzzle-piece: "\f12e";
|
||||||
@fa-var-qq: "\f1d6";
|
@fa-var-qq: "\f1d6";
|
||||||
@fa-var-qrcode: "\f029";
|
@fa-var-qrcode: "\f029";
|
||||||
@fa-var-question: "\f128";
|
@fa-var-question: "\f128";
|
||||||
@fa-var-question-circle: "\f059";
|
@fa-var-question-circle: "\f059";
|
||||||
@fa-var-question-circle-o: "\f29c";
|
|
||||||
@fa-var-quora: "\f2c4";
|
|
||||||
@fa-var-quote-left: "\f10d";
|
@fa-var-quote-left: "\f10d";
|
||||||
@fa-var-quote-right: "\f10e";
|
@fa-var-quote-right: "\f10e";
|
||||||
@fa-var-ra: "\f1d0";
|
@fa-var-ra: "\f1d0";
|
||||||
@fa-var-random: "\f074";
|
@fa-var-random: "\f074";
|
||||||
@fa-var-ravelry: "\f2d9";
|
|
||||||
@fa-var-rebel: "\f1d0";
|
@fa-var-rebel: "\f1d0";
|
||||||
@fa-var-recycle: "\f1b8";
|
@fa-var-recycle: "\f1b8";
|
||||||
@fa-var-reddit: "\f1a1";
|
@fa-var-reddit: "\f1a1";
|
||||||
@fa-var-reddit-alien: "\f281";
|
|
||||||
@fa-var-reddit-square: "\f1a2";
|
@fa-var-reddit-square: "\f1a2";
|
||||||
@fa-var-refresh: "\f021";
|
@fa-var-refresh: "\f021";
|
||||||
@fa-var-registered: "\f25d";
|
|
||||||
@fa-var-remove: "\f00d";
|
@fa-var-remove: "\f00d";
|
||||||
@fa-var-renren: "\f18b";
|
@fa-var-renren: "\f18b";
|
||||||
@fa-var-reorder: "\f0c9";
|
@fa-var-reorder: "\f0c9";
|
||||||
@fa-var-repeat: "\f01e";
|
@fa-var-repeat: "\f01e";
|
||||||
@fa-var-reply: "\f112";
|
@fa-var-reply: "\f112";
|
||||||
@fa-var-reply-all: "\f122";
|
@fa-var-reply-all: "\f122";
|
||||||
@fa-var-resistance: "\f1d0";
|
|
||||||
@fa-var-retweet: "\f079";
|
@fa-var-retweet: "\f079";
|
||||||
@fa-var-rmb: "\f157";
|
@fa-var-rmb: "\f157";
|
||||||
@fa-var-road: "\f018";
|
@fa-var-road: "\f018";
|
||||||
|
@ -568,18 +410,13 @@
|
||||||
@fa-var-rub: "\f158";
|
@fa-var-rub: "\f158";
|
||||||
@fa-var-ruble: "\f158";
|
@fa-var-ruble: "\f158";
|
||||||
@fa-var-rupee: "\f156";
|
@fa-var-rupee: "\f156";
|
||||||
@fa-var-s15: "\f2cd";
|
|
||||||
@fa-var-safari: "\f267";
|
|
||||||
@fa-var-save: "\f0c7";
|
@fa-var-save: "\f0c7";
|
||||||
@fa-var-scissors: "\f0c4";
|
@fa-var-scissors: "\f0c4";
|
||||||
@fa-var-scribd: "\f28a";
|
|
||||||
@fa-var-search: "\f002";
|
@fa-var-search: "\f002";
|
||||||
@fa-var-search-minus: "\f010";
|
@fa-var-search-minus: "\f010";
|
||||||
@fa-var-search-plus: "\f00e";
|
@fa-var-search-plus: "\f00e";
|
||||||
@fa-var-sellsy: "\f213";
|
|
||||||
@fa-var-send: "\f1d8";
|
@fa-var-send: "\f1d8";
|
||||||
@fa-var-send-o: "\f1d9";
|
@fa-var-send-o: "\f1d9";
|
||||||
@fa-var-server: "\f233";
|
|
||||||
@fa-var-share: "\f064";
|
@fa-var-share: "\f064";
|
||||||
@fa-var-share-alt: "\f1e0";
|
@fa-var-share-alt: "\f1e0";
|
||||||
@fa-var-share-alt-square: "\f1e1";
|
@fa-var-share-alt-square: "\f1e1";
|
||||||
|
@ -588,29 +425,16 @@
|
||||||
@fa-var-shekel: "\f20b";
|
@fa-var-shekel: "\f20b";
|
||||||
@fa-var-sheqel: "\f20b";
|
@fa-var-sheqel: "\f20b";
|
||||||
@fa-var-shield: "\f132";
|
@fa-var-shield: "\f132";
|
||||||
@fa-var-ship: "\f21a";
|
|
||||||
@fa-var-shirtsinbulk: "\f214";
|
|
||||||
@fa-var-shopping-bag: "\f290";
|
|
||||||
@fa-var-shopping-basket: "\f291";
|
|
||||||
@fa-var-shopping-cart: "\f07a";
|
@fa-var-shopping-cart: "\f07a";
|
||||||
@fa-var-shower: "\f2cc";
|
|
||||||
@fa-var-sign-in: "\f090";
|
@fa-var-sign-in: "\f090";
|
||||||
@fa-var-sign-language: "\f2a7";
|
|
||||||
@fa-var-sign-out: "\f08b";
|
@fa-var-sign-out: "\f08b";
|
||||||
@fa-var-signal: "\f012";
|
@fa-var-signal: "\f012";
|
||||||
@fa-var-signing: "\f2a7";
|
|
||||||
@fa-var-simplybuilt: "\f215";
|
|
||||||
@fa-var-sitemap: "\f0e8";
|
@fa-var-sitemap: "\f0e8";
|
||||||
@fa-var-skyatlas: "\f216";
|
|
||||||
@fa-var-skype: "\f17e";
|
@fa-var-skype: "\f17e";
|
||||||
@fa-var-slack: "\f198";
|
@fa-var-slack: "\f198";
|
||||||
@fa-var-sliders: "\f1de";
|
@fa-var-sliders: "\f1de";
|
||||||
@fa-var-slideshare: "\f1e7";
|
@fa-var-slideshare: "\f1e7";
|
||||||
@fa-var-smile-o: "\f118";
|
@fa-var-smile-o: "\f118";
|
||||||
@fa-var-snapchat: "\f2ab";
|
|
||||||
@fa-var-snapchat-ghost: "\f2ac";
|
|
||||||
@fa-var-snapchat-square: "\f2ad";
|
|
||||||
@fa-var-snowflake-o: "\f2dc";
|
|
||||||
@fa-var-soccer-ball-o: "\f1e3";
|
@fa-var-soccer-ball-o: "\f1e3";
|
||||||
@fa-var-sort: "\f0dc";
|
@fa-var-sort: "\f0dc";
|
||||||
@fa-var-sort-alpha-asc: "\f15d";
|
@fa-var-sort-alpha-asc: "\f15d";
|
||||||
|
@ -643,20 +467,13 @@
|
||||||
@fa-var-step-backward: "\f048";
|
@fa-var-step-backward: "\f048";
|
||||||
@fa-var-step-forward: "\f051";
|
@fa-var-step-forward: "\f051";
|
||||||
@fa-var-stethoscope: "\f0f1";
|
@fa-var-stethoscope: "\f0f1";
|
||||||
@fa-var-sticky-note: "\f249";
|
|
||||||
@fa-var-sticky-note-o: "\f24a";
|
|
||||||
@fa-var-stop: "\f04d";
|
@fa-var-stop: "\f04d";
|
||||||
@fa-var-stop-circle: "\f28d";
|
|
||||||
@fa-var-stop-circle-o: "\f28e";
|
|
||||||
@fa-var-street-view: "\f21d";
|
|
||||||
@fa-var-strikethrough: "\f0cc";
|
@fa-var-strikethrough: "\f0cc";
|
||||||
@fa-var-stumbleupon: "\f1a4";
|
@fa-var-stumbleupon: "\f1a4";
|
||||||
@fa-var-stumbleupon-circle: "\f1a3";
|
@fa-var-stumbleupon-circle: "\f1a3";
|
||||||
@fa-var-subscript: "\f12c";
|
@fa-var-subscript: "\f12c";
|
||||||
@fa-var-subway: "\f239";
|
|
||||||
@fa-var-suitcase: "\f0f2";
|
@fa-var-suitcase: "\f0f2";
|
||||||
@fa-var-sun-o: "\f185";
|
@fa-var-sun-o: "\f185";
|
||||||
@fa-var-superpowers: "\f2dd";
|
|
||||||
@fa-var-superscript: "\f12b";
|
@fa-var-superscript: "\f12b";
|
||||||
@fa-var-support: "\f1cd";
|
@fa-var-support: "\f1cd";
|
||||||
@fa-var-table: "\f0ce";
|
@fa-var-table: "\f0ce";
|
||||||
|
@ -666,8 +483,6 @@
|
||||||
@fa-var-tags: "\f02c";
|
@fa-var-tags: "\f02c";
|
||||||
@fa-var-tasks: "\f0ae";
|
@fa-var-tasks: "\f0ae";
|
||||||
@fa-var-taxi: "\f1ba";
|
@fa-var-taxi: "\f1ba";
|
||||||
@fa-var-telegram: "\f2c6";
|
|
||||||
@fa-var-television: "\f26c";
|
|
||||||
@fa-var-tencent-weibo: "\f1d5";
|
@fa-var-tencent-weibo: "\f1d5";
|
||||||
@fa-var-terminal: "\f120";
|
@fa-var-terminal: "\f120";
|
||||||
@fa-var-text-height: "\f034";
|
@fa-var-text-height: "\f034";
|
||||||
|
@ -675,18 +490,6 @@
|
||||||
@fa-var-th: "\f00a";
|
@fa-var-th: "\f00a";
|
||||||
@fa-var-th-large: "\f009";
|
@fa-var-th-large: "\f009";
|
||||||
@fa-var-th-list: "\f00b";
|
@fa-var-th-list: "\f00b";
|
||||||
@fa-var-themeisle: "\f2b2";
|
|
||||||
@fa-var-thermometer: "\f2c7";
|
|
||||||
@fa-var-thermometer-0: "\f2cb";
|
|
||||||
@fa-var-thermometer-1: "\f2ca";
|
|
||||||
@fa-var-thermometer-2: "\f2c9";
|
|
||||||
@fa-var-thermometer-3: "\f2c8";
|
|
||||||
@fa-var-thermometer-4: "\f2c7";
|
|
||||||
@fa-var-thermometer-empty: "\f2cb";
|
|
||||||
@fa-var-thermometer-full: "\f2c7";
|
|
||||||
@fa-var-thermometer-half: "\f2c9";
|
|
||||||
@fa-var-thermometer-quarter: "\f2ca";
|
|
||||||
@fa-var-thermometer-three-quarters: "\f2c8";
|
|
||||||
@fa-var-thumb-tack: "\f08d";
|
@fa-var-thumb-tack: "\f08d";
|
||||||
@fa-var-thumbs-down: "\f165";
|
@fa-var-thumbs-down: "\f165";
|
||||||
@fa-var-thumbs-o-down: "\f088";
|
@fa-var-thumbs-o-down: "\f088";
|
||||||
|
@ -696,8 +499,6 @@
|
||||||
@fa-var-times: "\f00d";
|
@fa-var-times: "\f00d";
|
||||||
@fa-var-times-circle: "\f057";
|
@fa-var-times-circle: "\f057";
|
||||||
@fa-var-times-circle-o: "\f05c";
|
@fa-var-times-circle-o: "\f05c";
|
||||||
@fa-var-times-rectangle: "\f2d3";
|
|
||||||
@fa-var-times-rectangle-o: "\f2d4";
|
|
||||||
@fa-var-tint: "\f043";
|
@fa-var-tint: "\f043";
|
||||||
@fa-var-toggle-down: "\f150";
|
@fa-var-toggle-down: "\f150";
|
||||||
@fa-var-toggle-left: "\f191";
|
@fa-var-toggle-left: "\f191";
|
||||||
|
@ -705,15 +506,10 @@
|
||||||
@fa-var-toggle-on: "\f205";
|
@fa-var-toggle-on: "\f205";
|
||||||
@fa-var-toggle-right: "\f152";
|
@fa-var-toggle-right: "\f152";
|
||||||
@fa-var-toggle-up: "\f151";
|
@fa-var-toggle-up: "\f151";
|
||||||
@fa-var-trademark: "\f25c";
|
|
||||||
@fa-var-train: "\f238";
|
|
||||||
@fa-var-transgender: "\f224";
|
|
||||||
@fa-var-transgender-alt: "\f225";
|
|
||||||
@fa-var-trash: "\f1f8";
|
@fa-var-trash: "\f1f8";
|
||||||
@fa-var-trash-o: "\f014";
|
@fa-var-trash-o: "\f014";
|
||||||
@fa-var-tree: "\f1bb";
|
@fa-var-tree: "\f1bb";
|
||||||
@fa-var-trello: "\f181";
|
@fa-var-trello: "\f181";
|
||||||
@fa-var-tripadvisor: "\f262";
|
|
||||||
@fa-var-trophy: "\f091";
|
@fa-var-trophy: "\f091";
|
||||||
@fa-var-truck: "\f0d1";
|
@fa-var-truck: "\f0d1";
|
||||||
@fa-var-try: "\f195";
|
@fa-var-try: "\f195";
|
||||||
|
@ -721,45 +517,26 @@
|
||||||
@fa-var-tumblr: "\f173";
|
@fa-var-tumblr: "\f173";
|
||||||
@fa-var-tumblr-square: "\f174";
|
@fa-var-tumblr-square: "\f174";
|
||||||
@fa-var-turkish-lira: "\f195";
|
@fa-var-turkish-lira: "\f195";
|
||||||
@fa-var-tv: "\f26c";
|
|
||||||
@fa-var-twitch: "\f1e8";
|
@fa-var-twitch: "\f1e8";
|
||||||
@fa-var-twitter: "\f099";
|
@fa-var-twitter: "\f099";
|
||||||
@fa-var-twitter-square: "\f081";
|
@fa-var-twitter-square: "\f081";
|
||||||
@fa-var-umbrella: "\f0e9";
|
@fa-var-umbrella: "\f0e9";
|
||||||
@fa-var-underline: "\f0cd";
|
@fa-var-underline: "\f0cd";
|
||||||
@fa-var-undo: "\f0e2";
|
@fa-var-undo: "\f0e2";
|
||||||
@fa-var-universal-access: "\f29a";
|
|
||||||
@fa-var-university: "\f19c";
|
@fa-var-university: "\f19c";
|
||||||
@fa-var-unlink: "\f127";
|
@fa-var-unlink: "\f127";
|
||||||
@fa-var-unlock: "\f09c";
|
@fa-var-unlock: "\f09c";
|
||||||
@fa-var-unlock-alt: "\f13e";
|
@fa-var-unlock-alt: "\f13e";
|
||||||
@fa-var-unsorted: "\f0dc";
|
@fa-var-unsorted: "\f0dc";
|
||||||
@fa-var-upload: "\f093";
|
@fa-var-upload: "\f093";
|
||||||
@fa-var-usb: "\f287";
|
|
||||||
@fa-var-usd: "\f155";
|
@fa-var-usd: "\f155";
|
||||||
@fa-var-user: "\f007";
|
@fa-var-user: "\f007";
|
||||||
@fa-var-user-circle: "\f2bd";
|
|
||||||
@fa-var-user-circle-o: "\f2be";
|
|
||||||
@fa-var-user-md: "\f0f0";
|
@fa-var-user-md: "\f0f0";
|
||||||
@fa-var-user-o: "\f2c0";
|
|
||||||
@fa-var-user-plus: "\f234";
|
|
||||||
@fa-var-user-secret: "\f21b";
|
|
||||||
@fa-var-user-times: "\f235";
|
|
||||||
@fa-var-users: "\f0c0";
|
@fa-var-users: "\f0c0";
|
||||||
@fa-var-vcard: "\f2bb";
|
|
||||||
@fa-var-vcard-o: "\f2bc";
|
|
||||||
@fa-var-venus: "\f221";
|
|
||||||
@fa-var-venus-double: "\f226";
|
|
||||||
@fa-var-venus-mars: "\f228";
|
|
||||||
@fa-var-viacoin: "\f237";
|
|
||||||
@fa-var-viadeo: "\f2a9";
|
|
||||||
@fa-var-viadeo-square: "\f2aa";
|
|
||||||
@fa-var-video-camera: "\f03d";
|
@fa-var-video-camera: "\f03d";
|
||||||
@fa-var-vimeo: "\f27d";
|
|
||||||
@fa-var-vimeo-square: "\f194";
|
@fa-var-vimeo-square: "\f194";
|
||||||
@fa-var-vine: "\f1ca";
|
@fa-var-vine: "\f1ca";
|
||||||
@fa-var-vk: "\f189";
|
@fa-var-vk: "\f189";
|
||||||
@fa-var-volume-control-phone: "\f2a0";
|
|
||||||
@fa-var-volume-down: "\f027";
|
@fa-var-volume-down: "\f027";
|
||||||
@fa-var-volume-off: "\f026";
|
@fa-var-volume-off: "\f026";
|
||||||
@fa-var-volume-up: "\f028";
|
@fa-var-volume-up: "\f028";
|
||||||
|
@ -767,33 +544,17 @@
|
||||||
@fa-var-wechat: "\f1d7";
|
@fa-var-wechat: "\f1d7";
|
||||||
@fa-var-weibo: "\f18a";
|
@fa-var-weibo: "\f18a";
|
||||||
@fa-var-weixin: "\f1d7";
|
@fa-var-weixin: "\f1d7";
|
||||||
@fa-var-whatsapp: "\f232";
|
|
||||||
@fa-var-wheelchair: "\f193";
|
@fa-var-wheelchair: "\f193";
|
||||||
@fa-var-wheelchair-alt: "\f29b";
|
|
||||||
@fa-var-wifi: "\f1eb";
|
@fa-var-wifi: "\f1eb";
|
||||||
@fa-var-wikipedia-w: "\f266";
|
|
||||||
@fa-var-window-close: "\f2d3";
|
|
||||||
@fa-var-window-close-o: "\f2d4";
|
|
||||||
@fa-var-window-maximize: "\f2d0";
|
|
||||||
@fa-var-window-minimize: "\f2d1";
|
|
||||||
@fa-var-window-restore: "\f2d2";
|
|
||||||
@fa-var-windows: "\f17a";
|
@fa-var-windows: "\f17a";
|
||||||
@fa-var-won: "\f159";
|
@fa-var-won: "\f159";
|
||||||
@fa-var-wordpress: "\f19a";
|
@fa-var-wordpress: "\f19a";
|
||||||
@fa-var-wpbeginner: "\f297";
|
|
||||||
@fa-var-wpexplorer: "\f2de";
|
|
||||||
@fa-var-wpforms: "\f298";
|
|
||||||
@fa-var-wrench: "\f0ad";
|
@fa-var-wrench: "\f0ad";
|
||||||
@fa-var-xing: "\f168";
|
@fa-var-xing: "\f168";
|
||||||
@fa-var-xing-square: "\f169";
|
@fa-var-xing-square: "\f169";
|
||||||
@fa-var-y-combinator: "\f23b";
|
|
||||||
@fa-var-y-combinator-square: "\f1d4";
|
|
||||||
@fa-var-yahoo: "\f19e";
|
@fa-var-yahoo: "\f19e";
|
||||||
@fa-var-yc: "\f23b";
|
|
||||||
@fa-var-yc-square: "\f1d4";
|
|
||||||
@fa-var-yelp: "\f1e9";
|
@fa-var-yelp: "\f1e9";
|
||||||
@fa-var-yen: "\f157";
|
@fa-var-yen: "\f157";
|
||||||
@fa-var-yoast: "\f2b1";
|
|
||||||
@fa-var-youtube: "\f167";
|
@fa-var-youtube: "\f167";
|
||||||
@fa-var-youtube-play: "\f16a";
|
@fa-var-youtube-play: "\f16a";
|
||||||
@fa-var-youtube-square: "\f166";
|
@fa-var-youtube-square: "\f166";
|
||||||
|
|
|
@ -7,15 +7,6 @@
|
||||||
border-radius: .1em;
|
border-radius: .1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.#{$fa-css-prefix}-pull-left { float: left; }
|
|
||||||
.#{$fa-css-prefix}-pull-right { float: right; }
|
|
||||||
|
|
||||||
.#{$fa-css-prefix} {
|
|
||||||
&.#{$fa-css-prefix}-pull-left { margin-right: .3em; }
|
|
||||||
&.#{$fa-css-prefix}-pull-right { margin-left: .3em; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deprecated as of 4.4.0 */
|
|
||||||
.pull-right { float: right; }
|
.pull-right { float: right; }
|
||||||
.pull-left { float: left; }
|
.pull-left { float: left; }
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,9 @@
|
||||||
|
|
||||||
.#{$fa-css-prefix} {
|
.#{$fa-css-prefix} {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
|
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,12 +158,10 @@
|
||||||
.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }
|
.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; }
|
||||||
.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }
|
.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; }
|
||||||
.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }
|
.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; }
|
||||||
.#{$fa-css-prefix}-facebook-f:before,
|
|
||||||
.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }
|
.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; }
|
||||||
.#{$fa-css-prefix}-github:before { content: $fa-var-github; }
|
.#{$fa-css-prefix}-github:before { content: $fa-var-github; }
|
||||||
.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }
|
.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; }
|
||||||
.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }
|
.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; }
|
||||||
.#{$fa-css-prefix}-feed:before,
|
|
||||||
.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }
|
.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; }
|
||||||
.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }
|
.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; }
|
||||||
.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }
|
.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; }
|
||||||
|
@ -399,8 +397,7 @@
|
||||||
.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }
|
.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; }
|
||||||
.#{$fa-css-prefix}-female:before { content: $fa-var-female; }
|
.#{$fa-css-prefix}-female:before { content: $fa-var-female; }
|
||||||
.#{$fa-css-prefix}-male:before { content: $fa-var-male; }
|
.#{$fa-css-prefix}-male:before { content: $fa-var-male; }
|
||||||
.#{$fa-css-prefix}-gittip:before,
|
.#{$fa-css-prefix}-gittip:before { content: $fa-var-gittip; }
|
||||||
.#{$fa-css-prefix}-gratipay:before { content: $fa-var-gratipay; }
|
|
||||||
.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }
|
.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; }
|
||||||
.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }
|
.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; }
|
||||||
.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }
|
.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; }
|
||||||
|
@ -438,7 +435,7 @@
|
||||||
.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }
|
.#{$fa-css-prefix}-stumbleupon:before { content: $fa-var-stumbleupon; }
|
||||||
.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }
|
.#{$fa-css-prefix}-delicious:before { content: $fa-var-delicious; }
|
||||||
.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }
|
.#{$fa-css-prefix}-digg:before { content: $fa-var-digg; }
|
||||||
.#{$fa-css-prefix}-pied-piper-pp:before { content: $fa-var-pied-piper-pp; }
|
.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
|
||||||
.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }
|
.#{$fa-css-prefix}-pied-piper-alt:before { content: $fa-var-pied-piper-alt; }
|
||||||
.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }
|
.#{$fa-css-prefix}-drupal:before { content: $fa-var-drupal; }
|
||||||
.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }
|
.#{$fa-css-prefix}-joomla:before { content: $fa-var-joomla; }
|
||||||
|
@ -488,14 +485,11 @@
|
||||||
.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }
|
.#{$fa-css-prefix}-life-ring:before { content: $fa-var-life-ring; }
|
||||||
.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }
|
.#{$fa-css-prefix}-circle-o-notch:before { content: $fa-var-circle-o-notch; }
|
||||||
.#{$fa-css-prefix}-ra:before,
|
.#{$fa-css-prefix}-ra:before,
|
||||||
.#{$fa-css-prefix}-resistance:before,
|
|
||||||
.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }
|
.#{$fa-css-prefix}-rebel:before { content: $fa-var-rebel; }
|
||||||
.#{$fa-css-prefix}-ge:before,
|
.#{$fa-css-prefix}-ge:before,
|
||||||
.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }
|
.#{$fa-css-prefix}-empire:before { content: $fa-var-empire; }
|
||||||
.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }
|
.#{$fa-css-prefix}-git-square:before { content: $fa-var-git-square; }
|
||||||
.#{$fa-css-prefix}-git:before { content: $fa-var-git; }
|
.#{$fa-css-prefix}-git:before { content: $fa-var-git; }
|
||||||
.#{$fa-css-prefix}-y-combinator-square:before,
|
|
||||||
.#{$fa-css-prefix}-yc-square:before,
|
|
||||||
.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }
|
.#{$fa-css-prefix}-hacker-news:before { content: $fa-var-hacker-news; }
|
||||||
.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }
|
.#{$fa-css-prefix}-tencent-weibo:before { content: $fa-var-tencent-weibo; }
|
||||||
.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }
|
.#{$fa-css-prefix}-qq:before { content: $fa-var-qq; }
|
||||||
|
@ -556,234 +550,3 @@
|
||||||
.#{$fa-css-prefix}-sheqel:before,
|
.#{$fa-css-prefix}-sheqel:before,
|
||||||
.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }
|
.#{$fa-css-prefix}-ils:before { content: $fa-var-ils; }
|
||||||
.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }
|
.#{$fa-css-prefix}-meanpath:before { content: $fa-var-meanpath; }
|
||||||
.#{$fa-css-prefix}-buysellads:before { content: $fa-var-buysellads; }
|
|
||||||
.#{$fa-css-prefix}-connectdevelop:before { content: $fa-var-connectdevelop; }
|
|
||||||
.#{$fa-css-prefix}-dashcube:before { content: $fa-var-dashcube; }
|
|
||||||
.#{$fa-css-prefix}-forumbee:before { content: $fa-var-forumbee; }
|
|
||||||
.#{$fa-css-prefix}-leanpub:before { content: $fa-var-leanpub; }
|
|
||||||
.#{$fa-css-prefix}-sellsy:before { content: $fa-var-sellsy; }
|
|
||||||
.#{$fa-css-prefix}-shirtsinbulk:before { content: $fa-var-shirtsinbulk; }
|
|
||||||
.#{$fa-css-prefix}-simplybuilt:before { content: $fa-var-simplybuilt; }
|
|
||||||
.#{$fa-css-prefix}-skyatlas:before { content: $fa-var-skyatlas; }
|
|
||||||
.#{$fa-css-prefix}-cart-plus:before { content: $fa-var-cart-plus; }
|
|
||||||
.#{$fa-css-prefix}-cart-arrow-down:before { content: $fa-var-cart-arrow-down; }
|
|
||||||
.#{$fa-css-prefix}-diamond:before { content: $fa-var-diamond; }
|
|
||||||
.#{$fa-css-prefix}-ship:before { content: $fa-var-ship; }
|
|
||||||
.#{$fa-css-prefix}-user-secret:before { content: $fa-var-user-secret; }
|
|
||||||
.#{$fa-css-prefix}-motorcycle:before { content: $fa-var-motorcycle; }
|
|
||||||
.#{$fa-css-prefix}-street-view:before { content: $fa-var-street-view; }
|
|
||||||
.#{$fa-css-prefix}-heartbeat:before { content: $fa-var-heartbeat; }
|
|
||||||
.#{$fa-css-prefix}-venus:before { content: $fa-var-venus; }
|
|
||||||
.#{$fa-css-prefix}-mars:before { content: $fa-var-mars; }
|
|
||||||
.#{$fa-css-prefix}-mercury:before { content: $fa-var-mercury; }
|
|
||||||
.#{$fa-css-prefix}-intersex:before,
|
|
||||||
.#{$fa-css-prefix}-transgender:before { content: $fa-var-transgender; }
|
|
||||||
.#{$fa-css-prefix}-transgender-alt:before { content: $fa-var-transgender-alt; }
|
|
||||||
.#{$fa-css-prefix}-venus-double:before { content: $fa-var-venus-double; }
|
|
||||||
.#{$fa-css-prefix}-mars-double:before { content: $fa-var-mars-double; }
|
|
||||||
.#{$fa-css-prefix}-venus-mars:before { content: $fa-var-venus-mars; }
|
|
||||||
.#{$fa-css-prefix}-mars-stroke:before { content: $fa-var-mars-stroke; }
|
|
||||||
.#{$fa-css-prefix}-mars-stroke-v:before { content: $fa-var-mars-stroke-v; }
|
|
||||||
.#{$fa-css-prefix}-mars-stroke-h:before { content: $fa-var-mars-stroke-h; }
|
|
||||||
.#{$fa-css-prefix}-neuter:before { content: $fa-var-neuter; }
|
|
||||||
.#{$fa-css-prefix}-genderless:before { content: $fa-var-genderless; }
|
|
||||||
.#{$fa-css-prefix}-facebook-official:before { content: $fa-var-facebook-official; }
|
|
||||||
.#{$fa-css-prefix}-pinterest-p:before { content: $fa-var-pinterest-p; }
|
|
||||||
.#{$fa-css-prefix}-whatsapp:before { content: $fa-var-whatsapp; }
|
|
||||||
.#{$fa-css-prefix}-server:before { content: $fa-var-server; }
|
|
||||||
.#{$fa-css-prefix}-user-plus:before { content: $fa-var-user-plus; }
|
|
||||||
.#{$fa-css-prefix}-user-times:before { content: $fa-var-user-times; }
|
|
||||||
.#{$fa-css-prefix}-hotel:before,
|
|
||||||
.#{$fa-css-prefix}-bed:before { content: $fa-var-bed; }
|
|
||||||
.#{$fa-css-prefix}-viacoin:before { content: $fa-var-viacoin; }
|
|
||||||
.#{$fa-css-prefix}-train:before { content: $fa-var-train; }
|
|
||||||
.#{$fa-css-prefix}-subway:before { content: $fa-var-subway; }
|
|
||||||
.#{$fa-css-prefix}-medium:before { content: $fa-var-medium; }
|
|
||||||
.#{$fa-css-prefix}-yc:before,
|
|
||||||
.#{$fa-css-prefix}-y-combinator:before { content: $fa-var-y-combinator; }
|
|
||||||
.#{$fa-css-prefix}-optin-monster:before { content: $fa-var-optin-monster; }
|
|
||||||
.#{$fa-css-prefix}-opencart:before { content: $fa-var-opencart; }
|
|
||||||
.#{$fa-css-prefix}-expeditedssl:before { content: $fa-var-expeditedssl; }
|
|
||||||
.#{$fa-css-prefix}-battery-4:before,
|
|
||||||
.#{$fa-css-prefix}-battery:before,
|
|
||||||
.#{$fa-css-prefix}-battery-full:before { content: $fa-var-battery-full; }
|
|
||||||
.#{$fa-css-prefix}-battery-3:before,
|
|
||||||
.#{$fa-css-prefix}-battery-three-quarters:before { content: $fa-var-battery-three-quarters; }
|
|
||||||
.#{$fa-css-prefix}-battery-2:before,
|
|
||||||
.#{$fa-css-prefix}-battery-half:before { content: $fa-var-battery-half; }
|
|
||||||
.#{$fa-css-prefix}-battery-1:before,
|
|
||||||
.#{$fa-css-prefix}-battery-quarter:before { content: $fa-var-battery-quarter; }
|
|
||||||
.#{$fa-css-prefix}-battery-0:before,
|
|
||||||
.#{$fa-css-prefix}-battery-empty:before { content: $fa-var-battery-empty; }
|
|
||||||
.#{$fa-css-prefix}-mouse-pointer:before { content: $fa-var-mouse-pointer; }
|
|
||||||
.#{$fa-css-prefix}-i-cursor:before { content: $fa-var-i-cursor; }
|
|
||||||
.#{$fa-css-prefix}-object-group:before { content: $fa-var-object-group; }
|
|
||||||
.#{$fa-css-prefix}-object-ungroup:before { content: $fa-var-object-ungroup; }
|
|
||||||
.#{$fa-css-prefix}-sticky-note:before { content: $fa-var-sticky-note; }
|
|
||||||
.#{$fa-css-prefix}-sticky-note-o:before { content: $fa-var-sticky-note-o; }
|
|
||||||
.#{$fa-css-prefix}-cc-jcb:before { content: $fa-var-cc-jcb; }
|
|
||||||
.#{$fa-css-prefix}-cc-diners-club:before { content: $fa-var-cc-diners-club; }
|
|
||||||
.#{$fa-css-prefix}-clone:before { content: $fa-var-clone; }
|
|
||||||
.#{$fa-css-prefix}-balance-scale:before { content: $fa-var-balance-scale; }
|
|
||||||
.#{$fa-css-prefix}-hourglass-o:before { content: $fa-var-hourglass-o; }
|
|
||||||
.#{$fa-css-prefix}-hourglass-1:before,
|
|
||||||
.#{$fa-css-prefix}-hourglass-start:before { content: $fa-var-hourglass-start; }
|
|
||||||
.#{$fa-css-prefix}-hourglass-2:before,
|
|
||||||
.#{$fa-css-prefix}-hourglass-half:before { content: $fa-var-hourglass-half; }
|
|
||||||
.#{$fa-css-prefix}-hourglass-3:before,
|
|
||||||
.#{$fa-css-prefix}-hourglass-end:before { content: $fa-var-hourglass-end; }
|
|
||||||
.#{$fa-css-prefix}-hourglass:before { content: $fa-var-hourglass; }
|
|
||||||
.#{$fa-css-prefix}-hand-grab-o:before,
|
|
||||||
.#{$fa-css-prefix}-hand-rock-o:before { content: $fa-var-hand-rock-o; }
|
|
||||||
.#{$fa-css-prefix}-hand-stop-o:before,
|
|
||||||
.#{$fa-css-prefix}-hand-paper-o:before { content: $fa-var-hand-paper-o; }
|
|
||||||
.#{$fa-css-prefix}-hand-scissors-o:before { content: $fa-var-hand-scissors-o; }
|
|
||||||
.#{$fa-css-prefix}-hand-lizard-o:before { content: $fa-var-hand-lizard-o; }
|
|
||||||
.#{$fa-css-prefix}-hand-spock-o:before { content: $fa-var-hand-spock-o; }
|
|
||||||
.#{$fa-css-prefix}-hand-pointer-o:before { content: $fa-var-hand-pointer-o; }
|
|
||||||
.#{$fa-css-prefix}-hand-peace-o:before { content: $fa-var-hand-peace-o; }
|
|
||||||
.#{$fa-css-prefix}-trademark:before { content: $fa-var-trademark; }
|
|
||||||
.#{$fa-css-prefix}-registered:before { content: $fa-var-registered; }
|
|
||||||
.#{$fa-css-prefix}-creative-commons:before { content: $fa-var-creative-commons; }
|
|
||||||
.#{$fa-css-prefix}-gg:before { content: $fa-var-gg; }
|
|
||||||
.#{$fa-css-prefix}-gg-circle:before { content: $fa-var-gg-circle; }
|
|
||||||
.#{$fa-css-prefix}-tripadvisor:before { content: $fa-var-tripadvisor; }
|
|
||||||
.#{$fa-css-prefix}-odnoklassniki:before { content: $fa-var-odnoklassniki; }
|
|
||||||
.#{$fa-css-prefix}-odnoklassniki-square:before { content: $fa-var-odnoklassniki-square; }
|
|
||||||
.#{$fa-css-prefix}-get-pocket:before { content: $fa-var-get-pocket; }
|
|
||||||
.#{$fa-css-prefix}-wikipedia-w:before { content: $fa-var-wikipedia-w; }
|
|
||||||
.#{$fa-css-prefix}-safari:before { content: $fa-var-safari; }
|
|
||||||
.#{$fa-css-prefix}-chrome:before { content: $fa-var-chrome; }
|
|
||||||
.#{$fa-css-prefix}-firefox:before { content: $fa-var-firefox; }
|
|
||||||
.#{$fa-css-prefix}-opera:before { content: $fa-var-opera; }
|
|
||||||
.#{$fa-css-prefix}-internet-explorer:before { content: $fa-var-internet-explorer; }
|
|
||||||
.#{$fa-css-prefix}-tv:before,
|
|
||||||
.#{$fa-css-prefix}-television:before { content: $fa-var-television; }
|
|
||||||
.#{$fa-css-prefix}-contao:before { content: $fa-var-contao; }
|
|
||||||
.#{$fa-css-prefix}-500px:before { content: $fa-var-500px; }
|
|
||||||
.#{$fa-css-prefix}-amazon:before { content: $fa-var-amazon; }
|
|
||||||
.#{$fa-css-prefix}-calendar-plus-o:before { content: $fa-var-calendar-plus-o; }
|
|
||||||
.#{$fa-css-prefix}-calendar-minus-o:before { content: $fa-var-calendar-minus-o; }
|
|
||||||
.#{$fa-css-prefix}-calendar-times-o:before { content: $fa-var-calendar-times-o; }
|
|
||||||
.#{$fa-css-prefix}-calendar-check-o:before { content: $fa-var-calendar-check-o; }
|
|
||||||
.#{$fa-css-prefix}-industry:before { content: $fa-var-industry; }
|
|
||||||
.#{$fa-css-prefix}-map-pin:before { content: $fa-var-map-pin; }
|
|
||||||
.#{$fa-css-prefix}-map-signs:before { content: $fa-var-map-signs; }
|
|
||||||
.#{$fa-css-prefix}-map-o:before { content: $fa-var-map-o; }
|
|
||||||
.#{$fa-css-prefix}-map:before { content: $fa-var-map; }
|
|
||||||
.#{$fa-css-prefix}-commenting:before { content: $fa-var-commenting; }
|
|
||||||
.#{$fa-css-prefix}-commenting-o:before { content: $fa-var-commenting-o; }
|
|
||||||
.#{$fa-css-prefix}-houzz:before { content: $fa-var-houzz; }
|
|
||||||
.#{$fa-css-prefix}-vimeo:before { content: $fa-var-vimeo; }
|
|
||||||
.#{$fa-css-prefix}-black-tie:before { content: $fa-var-black-tie; }
|
|
||||||
.#{$fa-css-prefix}-fonticons:before { content: $fa-var-fonticons; }
|
|
||||||
.#{$fa-css-prefix}-reddit-alien:before { content: $fa-var-reddit-alien; }
|
|
||||||
.#{$fa-css-prefix}-edge:before { content: $fa-var-edge; }
|
|
||||||
.#{$fa-css-prefix}-credit-card-alt:before { content: $fa-var-credit-card-alt; }
|
|
||||||
.#{$fa-css-prefix}-codiepie:before { content: $fa-var-codiepie; }
|
|
||||||
.#{$fa-css-prefix}-modx:before { content: $fa-var-modx; }
|
|
||||||
.#{$fa-css-prefix}-fort-awesome:before { content: $fa-var-fort-awesome; }
|
|
||||||
.#{$fa-css-prefix}-usb:before { content: $fa-var-usb; }
|
|
||||||
.#{$fa-css-prefix}-product-hunt:before { content: $fa-var-product-hunt; }
|
|
||||||
.#{$fa-css-prefix}-mixcloud:before { content: $fa-var-mixcloud; }
|
|
||||||
.#{$fa-css-prefix}-scribd:before { content: $fa-var-scribd; }
|
|
||||||
.#{$fa-css-prefix}-pause-circle:before { content: $fa-var-pause-circle; }
|
|
||||||
.#{$fa-css-prefix}-pause-circle-o:before { content: $fa-var-pause-circle-o; }
|
|
||||||
.#{$fa-css-prefix}-stop-circle:before { content: $fa-var-stop-circle; }
|
|
||||||
.#{$fa-css-prefix}-stop-circle-o:before { content: $fa-var-stop-circle-o; }
|
|
||||||
.#{$fa-css-prefix}-shopping-bag:before { content: $fa-var-shopping-bag; }
|
|
||||||
.#{$fa-css-prefix}-shopping-basket:before { content: $fa-var-shopping-basket; }
|
|
||||||
.#{$fa-css-prefix}-hashtag:before { content: $fa-var-hashtag; }
|
|
||||||
.#{$fa-css-prefix}-bluetooth:before { content: $fa-var-bluetooth; }
|
|
||||||
.#{$fa-css-prefix}-bluetooth-b:before { content: $fa-var-bluetooth-b; }
|
|
||||||
.#{$fa-css-prefix}-percent:before { content: $fa-var-percent; }
|
|
||||||
.#{$fa-css-prefix}-gitlab:before { content: $fa-var-gitlab; }
|
|
||||||
.#{$fa-css-prefix}-wpbeginner:before { content: $fa-var-wpbeginner; }
|
|
||||||
.#{$fa-css-prefix}-wpforms:before { content: $fa-var-wpforms; }
|
|
||||||
.#{$fa-css-prefix}-envira:before { content: $fa-var-envira; }
|
|
||||||
.#{$fa-css-prefix}-universal-access:before { content: $fa-var-universal-access; }
|
|
||||||
.#{$fa-css-prefix}-wheelchair-alt:before { content: $fa-var-wheelchair-alt; }
|
|
||||||
.#{$fa-css-prefix}-question-circle-o:before { content: $fa-var-question-circle-o; }
|
|
||||||
.#{$fa-css-prefix}-blind:before { content: $fa-var-blind; }
|
|
||||||
.#{$fa-css-prefix}-audio-description:before { content: $fa-var-audio-description; }
|
|
||||||
.#{$fa-css-prefix}-volume-control-phone:before { content: $fa-var-volume-control-phone; }
|
|
||||||
.#{$fa-css-prefix}-braille:before { content: $fa-var-braille; }
|
|
||||||
.#{$fa-css-prefix}-assistive-listening-systems:before { content: $fa-var-assistive-listening-systems; }
|
|
||||||
.#{$fa-css-prefix}-asl-interpreting:before,
|
|
||||||
.#{$fa-css-prefix}-american-sign-language-interpreting:before { content: $fa-var-american-sign-language-interpreting; }
|
|
||||||
.#{$fa-css-prefix}-deafness:before,
|
|
||||||
.#{$fa-css-prefix}-hard-of-hearing:before,
|
|
||||||
.#{$fa-css-prefix}-deaf:before { content: $fa-var-deaf; }
|
|
||||||
.#{$fa-css-prefix}-glide:before { content: $fa-var-glide; }
|
|
||||||
.#{$fa-css-prefix}-glide-g:before { content: $fa-var-glide-g; }
|
|
||||||
.#{$fa-css-prefix}-signing:before,
|
|
||||||
.#{$fa-css-prefix}-sign-language:before { content: $fa-var-sign-language; }
|
|
||||||
.#{$fa-css-prefix}-low-vision:before { content: $fa-var-low-vision; }
|
|
||||||
.#{$fa-css-prefix}-viadeo:before { content: $fa-var-viadeo; }
|
|
||||||
.#{$fa-css-prefix}-viadeo-square:before { content: $fa-var-viadeo-square; }
|
|
||||||
.#{$fa-css-prefix}-snapchat:before { content: $fa-var-snapchat; }
|
|
||||||
.#{$fa-css-prefix}-snapchat-ghost:before { content: $fa-var-snapchat-ghost; }
|
|
||||||
.#{$fa-css-prefix}-snapchat-square:before { content: $fa-var-snapchat-square; }
|
|
||||||
.#{$fa-css-prefix}-pied-piper:before { content: $fa-var-pied-piper; }
|
|
||||||
.#{$fa-css-prefix}-first-order:before { content: $fa-var-first-order; }
|
|
||||||
.#{$fa-css-prefix}-yoast:before { content: $fa-var-yoast; }
|
|
||||||
.#{$fa-css-prefix}-themeisle:before { content: $fa-var-themeisle; }
|
|
||||||
.#{$fa-css-prefix}-google-plus-circle:before,
|
|
||||||
.#{$fa-css-prefix}-google-plus-official:before { content: $fa-var-google-plus-official; }
|
|
||||||
.#{$fa-css-prefix}-fa:before,
|
|
||||||
.#{$fa-css-prefix}-font-awesome:before { content: $fa-var-font-awesome; }
|
|
||||||
.#{$fa-css-prefix}-handshake-o:before { content: $fa-var-handshake-o; }
|
|
||||||
.#{$fa-css-prefix}-envelope-open:before { content: $fa-var-envelope-open; }
|
|
||||||
.#{$fa-css-prefix}-envelope-open-o:before { content: $fa-var-envelope-open-o; }
|
|
||||||
.#{$fa-css-prefix}-linode:before { content: $fa-var-linode; }
|
|
||||||
.#{$fa-css-prefix}-address-book:before { content: $fa-var-address-book; }
|
|
||||||
.#{$fa-css-prefix}-address-book-o:before { content: $fa-var-address-book-o; }
|
|
||||||
.#{$fa-css-prefix}-vcard:before,
|
|
||||||
.#{$fa-css-prefix}-address-card:before { content: $fa-var-address-card; }
|
|
||||||
.#{$fa-css-prefix}-vcard-o:before,
|
|
||||||
.#{$fa-css-prefix}-address-card-o:before { content: $fa-var-address-card-o; }
|
|
||||||
.#{$fa-css-prefix}-user-circle:before { content: $fa-var-user-circle; }
|
|
||||||
.#{$fa-css-prefix}-user-circle-o:before { content: $fa-var-user-circle-o; }
|
|
||||||
.#{$fa-css-prefix}-user-o:before { content: $fa-var-user-o; }
|
|
||||||
.#{$fa-css-prefix}-id-badge:before { content: $fa-var-id-badge; }
|
|
||||||
.#{$fa-css-prefix}-drivers-license:before,
|
|
||||||
.#{$fa-css-prefix}-id-card:before { content: $fa-var-id-card; }
|
|
||||||
.#{$fa-css-prefix}-drivers-license-o:before,
|
|
||||||
.#{$fa-css-prefix}-id-card-o:before { content: $fa-var-id-card-o; }
|
|
||||||
.#{$fa-css-prefix}-quora:before { content: $fa-var-quora; }
|
|
||||||
.#{$fa-css-prefix}-free-code-camp:before { content: $fa-var-free-code-camp; }
|
|
||||||
.#{$fa-css-prefix}-telegram:before { content: $fa-var-telegram; }
|
|
||||||
.#{$fa-css-prefix}-thermometer-4:before,
|
|
||||||
.#{$fa-css-prefix}-thermometer:before,
|
|
||||||
.#{$fa-css-prefix}-thermometer-full:before { content: $fa-var-thermometer-full; }
|
|
||||||
.#{$fa-css-prefix}-thermometer-3:before,
|
|
||||||
.#{$fa-css-prefix}-thermometer-three-quarters:before { content: $fa-var-thermometer-three-quarters; }
|
|
||||||
.#{$fa-css-prefix}-thermometer-2:before,
|
|
||||||
.#{$fa-css-prefix}-thermometer-half:before { content: $fa-var-thermometer-half; }
|
|
||||||
.#{$fa-css-prefix}-thermometer-1:before,
|
|
||||||
.#{$fa-css-prefix}-thermometer-quarter:before { content: $fa-var-thermometer-quarter; }
|
|
||||||
.#{$fa-css-prefix}-thermometer-0:before,
|
|
||||||
.#{$fa-css-prefix}-thermometer-empty:before { content: $fa-var-thermometer-empty; }
|
|
||||||
.#{$fa-css-prefix}-shower:before { content: $fa-var-shower; }
|
|
||||||
.#{$fa-css-prefix}-bathtub:before,
|
|
||||||
.#{$fa-css-prefix}-s15:before,
|
|
||||||
.#{$fa-css-prefix}-bath:before { content: $fa-var-bath; }
|
|
||||||
.#{$fa-css-prefix}-podcast:before { content: $fa-var-podcast; }
|
|
||||||
.#{$fa-css-prefix}-window-maximize:before { content: $fa-var-window-maximize; }
|
|
||||||
.#{$fa-css-prefix}-window-minimize:before { content: $fa-var-window-minimize; }
|
|
||||||
.#{$fa-css-prefix}-window-restore:before { content: $fa-var-window-restore; }
|
|
||||||
.#{$fa-css-prefix}-times-rectangle:before,
|
|
||||||
.#{$fa-css-prefix}-window-close:before { content: $fa-var-window-close; }
|
|
||||||
.#{$fa-css-prefix}-times-rectangle-o:before,
|
|
||||||
.#{$fa-css-prefix}-window-close-o:before { content: $fa-var-window-close-o; }
|
|
||||||
.#{$fa-css-prefix}-bandcamp:before { content: $fa-var-bandcamp; }
|
|
||||||
.#{$fa-css-prefix}-grav:before { content: $fa-var-grav; }
|
|
||||||
.#{$fa-css-prefix}-etsy:before { content: $fa-var-etsy; }
|
|
||||||
.#{$fa-css-prefix}-imdb:before { content: $fa-var-imdb; }
|
|
||||||
.#{$fa-css-prefix}-ravelry:before { content: $fa-var-ravelry; }
|
|
||||||
.#{$fa-css-prefix}-eercast:before { content: $fa-var-eercast; }
|
|
||||||
.#{$fa-css-prefix}-microchip:before { content: $fa-var-microchip; }
|
|
||||||
.#{$fa-css-prefix}-snowflake-o:before { content: $fa-var-snowflake-o; }
|
|
||||||
.#{$fa-css-prefix}-superpowers:before { content: $fa-var-superpowers; }
|
|
||||||
.#{$fa-css-prefix}-wpexplorer:before { content: $fa-var-wpexplorer; }
|
|
||||||
.#{$fa-css-prefix}-meetup:before { content: $fa-var-meetup; }
|
|
||||||
|
|
|
@ -3,58 +3,23 @@
|
||||||
|
|
||||||
@mixin fa-icon() {
|
@mixin fa-icon() {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration
|
font: normal normal normal 14px/1 FontAwesome; // shortening font declaration
|
||||||
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
font-size: inherit; // can't have font-size inherit on line above, so need to override
|
||||||
text-rendering: auto; // optimizelegibility throws things off #1094
|
text-rendering: auto; // optimizelegibility throws things off #1094
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin fa-icon-rotate($degrees, $rotation) {
|
@mixin fa-icon-rotate($degrees, $rotation) {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation})";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
|
||||||
-webkit-transform: rotate($degrees);
|
-webkit-transform: rotate($degrees);
|
||||||
-ms-transform: rotate($degrees);
|
-ms-transform: rotate($degrees);
|
||||||
transform: rotate($degrees);
|
transform: rotate($degrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin fa-icon-flip($horiz, $vert, $rotation) {
|
@mixin fa-icon-flip($horiz, $vert, $rotation) {
|
||||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation}, mirror=1)";
|
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
|
||||||
-webkit-transform: scale($horiz, $vert);
|
-webkit-transform: scale($horiz, $vert);
|
||||||
-ms-transform: scale($horiz, $vert);
|
-ms-transform: scale($horiz, $vert);
|
||||||
transform: scale($horiz, $vert);
|
transform: scale($horiz, $vert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Only display content to screen readers. A la Bootstrap 4.
|
|
||||||
//
|
|
||||||
// See: http://a11yproject.com/posts/how-to-hide-content/
|
|
||||||
|
|
||||||
@mixin sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0,0,0,0);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use in conjunction with .sr-only to only display content when it's focused.
|
|
||||||
//
|
|
||||||
// Useful for "Skip to main content" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1
|
|
||||||
//
|
|
||||||
// Credit: HTML5 Boilerplate
|
|
||||||
|
|
||||||
@mixin sr-only-focusable {
|
|
||||||
&:active,
|
|
||||||
&:focus {
|
|
||||||
position: static;
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
margin: 0;
|
|
||||||
overflow: visible;
|
|
||||||
clip: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
font-family: 'FontAwesome';
|
font-family: 'FontAwesome';
|
||||||
src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
|
src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}');
|
||||||
src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
|
src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'),
|
||||||
url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'),
|
|
||||||
url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
|
url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'),
|
||||||
url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
|
url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'),
|
||||||
url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
|
url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg');
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
// Screen Readers
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
.sr-only { @include sr-only(); }
|
|
||||||
.sr-only-focusable { @include sr-only-focusable(); }
|
|
|
@ -6,11 +6,6 @@
|
||||||
animation: fa-spin 2s infinite linear;
|
animation: fa-spin 2s infinite linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
.#{$fa-css-prefix}-pulse {
|
|
||||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
|
||||||
animation: fa-spin 1s infinite steps(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes fa-spin {
|
@-webkit-keyframes fa-spin {
|
||||||
0% {
|
0% {
|
||||||
-webkit-transform: rotate(0deg);
|
-webkit-transform: rotate(0deg);
|
|
@ -2,29 +2,20 @@
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
|
||||||
$fa-font-path: "../fonts" !default;
|
$fa-font-path: "../fonts" !default;
|
||||||
$fa-font-size-base: 14px !default;
|
//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.2.0/fonts" !default; // for referencing Bootstrap CDN font files directly
|
||||||
$fa-line-height-base: 1 !default;
|
|
||||||
//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.7.0/fonts" !default; // for referencing Bootstrap CDN font files directly
|
|
||||||
$fa-css-prefix: fa !default;
|
$fa-css-prefix: fa !default;
|
||||||
$fa-version: "4.7.0" !default;
|
$fa-version: "4.2.0" !default;
|
||||||
$fa-border-color: #eee !default;
|
$fa-border-color: #eee !default;
|
||||||
$fa-inverse: #fff !default;
|
$fa-inverse: #fff !default;
|
||||||
$fa-li-width: (30em / 14) !default;
|
$fa-li-width: (30em / 14) !default;
|
||||||
|
|
||||||
$fa-var-500px: "\f26e";
|
|
||||||
$fa-var-address-book: "\f2b9";
|
|
||||||
$fa-var-address-book-o: "\f2ba";
|
|
||||||
$fa-var-address-card: "\f2bb";
|
|
||||||
$fa-var-address-card-o: "\f2bc";
|
|
||||||
$fa-var-adjust: "\f042";
|
$fa-var-adjust: "\f042";
|
||||||
$fa-var-adn: "\f170";
|
$fa-var-adn: "\f170";
|
||||||
$fa-var-align-center: "\f037";
|
$fa-var-align-center: "\f037";
|
||||||
$fa-var-align-justify: "\f039";
|
$fa-var-align-justify: "\f039";
|
||||||
$fa-var-align-left: "\f036";
|
$fa-var-align-left: "\f036";
|
||||||
$fa-var-align-right: "\f038";
|
$fa-var-align-right: "\f038";
|
||||||
$fa-var-amazon: "\f270";
|
|
||||||
$fa-var-ambulance: "\f0f9";
|
$fa-var-ambulance: "\f0f9";
|
||||||
$fa-var-american-sign-language-interpreting: "\f2a3";
|
|
||||||
$fa-var-anchor: "\f13d";
|
$fa-var-anchor: "\f13d";
|
||||||
$fa-var-android: "\f17b";
|
$fa-var-android: "\f17b";
|
||||||
$fa-var-angellist: "\f209";
|
$fa-var-angellist: "\f209";
|
||||||
|
@ -55,35 +46,16 @@ $fa-var-arrows: "\f047";
|
||||||
$fa-var-arrows-alt: "\f0b2";
|
$fa-var-arrows-alt: "\f0b2";
|
||||||
$fa-var-arrows-h: "\f07e";
|
$fa-var-arrows-h: "\f07e";
|
||||||
$fa-var-arrows-v: "\f07d";
|
$fa-var-arrows-v: "\f07d";
|
||||||
$fa-var-asl-interpreting: "\f2a3";
|
|
||||||
$fa-var-assistive-listening-systems: "\f2a2";
|
|
||||||
$fa-var-asterisk: "\f069";
|
$fa-var-asterisk: "\f069";
|
||||||
$fa-var-at: "\f1fa";
|
$fa-var-at: "\f1fa";
|
||||||
$fa-var-audio-description: "\f29e";
|
|
||||||
$fa-var-automobile: "\f1b9";
|
$fa-var-automobile: "\f1b9";
|
||||||
$fa-var-backward: "\f04a";
|
$fa-var-backward: "\f04a";
|
||||||
$fa-var-balance-scale: "\f24e";
|
|
||||||
$fa-var-ban: "\f05e";
|
$fa-var-ban: "\f05e";
|
||||||
$fa-var-bandcamp: "\f2d5";
|
|
||||||
$fa-var-bank: "\f19c";
|
$fa-var-bank: "\f19c";
|
||||||
$fa-var-bar-chart: "\f080";
|
$fa-var-bar-chart: "\f080";
|
||||||
$fa-var-bar-chart-o: "\f080";
|
$fa-var-bar-chart-o: "\f080";
|
||||||
$fa-var-barcode: "\f02a";
|
$fa-var-barcode: "\f02a";
|
||||||
$fa-var-bars: "\f0c9";
|
$fa-var-bars: "\f0c9";
|
||||||
$fa-var-bath: "\f2cd";
|
|
||||||
$fa-var-bathtub: "\f2cd";
|
|
||||||
$fa-var-battery: "\f240";
|
|
||||||
$fa-var-battery-0: "\f244";
|
|
||||||
$fa-var-battery-1: "\f243";
|
|
||||||
$fa-var-battery-2: "\f242";
|
|
||||||
$fa-var-battery-3: "\f241";
|
|
||||||
$fa-var-battery-4: "\f240";
|
|
||||||
$fa-var-battery-empty: "\f244";
|
|
||||||
$fa-var-battery-full: "\f240";
|
|
||||||
$fa-var-battery-half: "\f242";
|
|
||||||
$fa-var-battery-quarter: "\f243";
|
|
||||||
$fa-var-battery-three-quarters: "\f241";
|
|
||||||
$fa-var-bed: "\f236";
|
|
||||||
$fa-var-beer: "\f0fc";
|
$fa-var-beer: "\f0fc";
|
||||||
$fa-var-behance: "\f1b4";
|
$fa-var-behance: "\f1b4";
|
||||||
$fa-var-behance-square: "\f1b5";
|
$fa-var-behance-square: "\f1b5";
|
||||||
|
@ -97,17 +69,12 @@ $fa-var-birthday-cake: "\f1fd";
|
||||||
$fa-var-bitbucket: "\f171";
|
$fa-var-bitbucket: "\f171";
|
||||||
$fa-var-bitbucket-square: "\f172";
|
$fa-var-bitbucket-square: "\f172";
|
||||||
$fa-var-bitcoin: "\f15a";
|
$fa-var-bitcoin: "\f15a";
|
||||||
$fa-var-black-tie: "\f27e";
|
|
||||||
$fa-var-blind: "\f29d";
|
|
||||||
$fa-var-bluetooth: "\f293";
|
|
||||||
$fa-var-bluetooth-b: "\f294";
|
|
||||||
$fa-var-bold: "\f032";
|
$fa-var-bold: "\f032";
|
||||||
$fa-var-bolt: "\f0e7";
|
$fa-var-bolt: "\f0e7";
|
||||||
$fa-var-bomb: "\f1e2";
|
$fa-var-bomb: "\f1e2";
|
||||||
$fa-var-book: "\f02d";
|
$fa-var-book: "\f02d";
|
||||||
$fa-var-bookmark: "\f02e";
|
$fa-var-bookmark: "\f02e";
|
||||||
$fa-var-bookmark-o: "\f097";
|
$fa-var-bookmark-o: "\f097";
|
||||||
$fa-var-braille: "\f2a1";
|
|
||||||
$fa-var-briefcase: "\f0b1";
|
$fa-var-briefcase: "\f0b1";
|
||||||
$fa-var-btc: "\f15a";
|
$fa-var-btc: "\f15a";
|
||||||
$fa-var-bug: "\f188";
|
$fa-var-bug: "\f188";
|
||||||
|
@ -116,15 +83,10 @@ $fa-var-building-o: "\f0f7";
|
||||||
$fa-var-bullhorn: "\f0a1";
|
$fa-var-bullhorn: "\f0a1";
|
||||||
$fa-var-bullseye: "\f140";
|
$fa-var-bullseye: "\f140";
|
||||||
$fa-var-bus: "\f207";
|
$fa-var-bus: "\f207";
|
||||||
$fa-var-buysellads: "\f20d";
|
|
||||||
$fa-var-cab: "\f1ba";
|
$fa-var-cab: "\f1ba";
|
||||||
$fa-var-calculator: "\f1ec";
|
$fa-var-calculator: "\f1ec";
|
||||||
$fa-var-calendar: "\f073";
|
$fa-var-calendar: "\f073";
|
||||||
$fa-var-calendar-check-o: "\f274";
|
|
||||||
$fa-var-calendar-minus-o: "\f272";
|
|
||||||
$fa-var-calendar-o: "\f133";
|
$fa-var-calendar-o: "\f133";
|
||||||
$fa-var-calendar-plus-o: "\f271";
|
|
||||||
$fa-var-calendar-times-o: "\f273";
|
|
||||||
$fa-var-camera: "\f030";
|
$fa-var-camera: "\f030";
|
||||||
$fa-var-camera-retro: "\f083";
|
$fa-var-camera-retro: "\f083";
|
||||||
$fa-var-car: "\f1b9";
|
$fa-var-car: "\f1b9";
|
||||||
|
@ -136,13 +98,9 @@ $fa-var-caret-square-o-left: "\f191";
|
||||||
$fa-var-caret-square-o-right: "\f152";
|
$fa-var-caret-square-o-right: "\f152";
|
||||||
$fa-var-caret-square-o-up: "\f151";
|
$fa-var-caret-square-o-up: "\f151";
|
||||||
$fa-var-caret-up: "\f0d8";
|
$fa-var-caret-up: "\f0d8";
|
||||||
$fa-var-cart-arrow-down: "\f218";
|
|
||||||
$fa-var-cart-plus: "\f217";
|
|
||||||
$fa-var-cc: "\f20a";
|
$fa-var-cc: "\f20a";
|
||||||
$fa-var-cc-amex: "\f1f3";
|
$fa-var-cc-amex: "\f1f3";
|
||||||
$fa-var-cc-diners-club: "\f24c";
|
|
||||||
$fa-var-cc-discover: "\f1f2";
|
$fa-var-cc-discover: "\f1f2";
|
||||||
$fa-var-cc-jcb: "\f24b";
|
|
||||||
$fa-var-cc-mastercard: "\f1f1";
|
$fa-var-cc-mastercard: "\f1f1";
|
||||||
$fa-var-cc-paypal: "\f1f4";
|
$fa-var-cc-paypal: "\f1f4";
|
||||||
$fa-var-cc-stripe: "\f1f5";
|
$fa-var-cc-stripe: "\f1f5";
|
||||||
|
@ -164,14 +122,12 @@ $fa-var-chevron-left: "\f053";
|
||||||
$fa-var-chevron-right: "\f054";
|
$fa-var-chevron-right: "\f054";
|
||||||
$fa-var-chevron-up: "\f077";
|
$fa-var-chevron-up: "\f077";
|
||||||
$fa-var-child: "\f1ae";
|
$fa-var-child: "\f1ae";
|
||||||
$fa-var-chrome: "\f268";
|
|
||||||
$fa-var-circle: "\f111";
|
$fa-var-circle: "\f111";
|
||||||
$fa-var-circle-o: "\f10c";
|
$fa-var-circle-o: "\f10c";
|
||||||
$fa-var-circle-o-notch: "\f1ce";
|
$fa-var-circle-o-notch: "\f1ce";
|
||||||
$fa-var-circle-thin: "\f1db";
|
$fa-var-circle-thin: "\f1db";
|
||||||
$fa-var-clipboard: "\f0ea";
|
$fa-var-clipboard: "\f0ea";
|
||||||
$fa-var-clock-o: "\f017";
|
$fa-var-clock-o: "\f017";
|
||||||
$fa-var-clone: "\f24d";
|
|
||||||
$fa-var-close: "\f00d";
|
$fa-var-close: "\f00d";
|
||||||
$fa-var-cloud: "\f0c2";
|
$fa-var-cloud: "\f0c2";
|
||||||
$fa-var-cloud-download: "\f0ed";
|
$fa-var-cloud-download: "\f0ed";
|
||||||
|
@ -180,26 +136,19 @@ $fa-var-cny: "\f157";
|
||||||
$fa-var-code: "\f121";
|
$fa-var-code: "\f121";
|
||||||
$fa-var-code-fork: "\f126";
|
$fa-var-code-fork: "\f126";
|
||||||
$fa-var-codepen: "\f1cb";
|
$fa-var-codepen: "\f1cb";
|
||||||
$fa-var-codiepie: "\f284";
|
|
||||||
$fa-var-coffee: "\f0f4";
|
$fa-var-coffee: "\f0f4";
|
||||||
$fa-var-cog: "\f013";
|
$fa-var-cog: "\f013";
|
||||||
$fa-var-cogs: "\f085";
|
$fa-var-cogs: "\f085";
|
||||||
$fa-var-columns: "\f0db";
|
$fa-var-columns: "\f0db";
|
||||||
$fa-var-comment: "\f075";
|
$fa-var-comment: "\f075";
|
||||||
$fa-var-comment-o: "\f0e5";
|
$fa-var-comment-o: "\f0e5";
|
||||||
$fa-var-commenting: "\f27a";
|
|
||||||
$fa-var-commenting-o: "\f27b";
|
|
||||||
$fa-var-comments: "\f086";
|
$fa-var-comments: "\f086";
|
||||||
$fa-var-comments-o: "\f0e6";
|
$fa-var-comments-o: "\f0e6";
|
||||||
$fa-var-compass: "\f14e";
|
$fa-var-compass: "\f14e";
|
||||||
$fa-var-compress: "\f066";
|
$fa-var-compress: "\f066";
|
||||||
$fa-var-connectdevelop: "\f20e";
|
|
||||||
$fa-var-contao: "\f26d";
|
|
||||||
$fa-var-copy: "\f0c5";
|
$fa-var-copy: "\f0c5";
|
||||||
$fa-var-copyright: "\f1f9";
|
$fa-var-copyright: "\f1f9";
|
||||||
$fa-var-creative-commons: "\f25e";
|
|
||||||
$fa-var-credit-card: "\f09d";
|
$fa-var-credit-card: "\f09d";
|
||||||
$fa-var-credit-card-alt: "\f283";
|
|
||||||
$fa-var-crop: "\f125";
|
$fa-var-crop: "\f125";
|
||||||
$fa-var-crosshairs: "\f05b";
|
$fa-var-crosshairs: "\f05b";
|
||||||
$fa-var-css3: "\f13c";
|
$fa-var-css3: "\f13c";
|
||||||
|
@ -208,39 +157,27 @@ $fa-var-cubes: "\f1b3";
|
||||||
$fa-var-cut: "\f0c4";
|
$fa-var-cut: "\f0c4";
|
||||||
$fa-var-cutlery: "\f0f5";
|
$fa-var-cutlery: "\f0f5";
|
||||||
$fa-var-dashboard: "\f0e4";
|
$fa-var-dashboard: "\f0e4";
|
||||||
$fa-var-dashcube: "\f210";
|
|
||||||
$fa-var-database: "\f1c0";
|
$fa-var-database: "\f1c0";
|
||||||
$fa-var-deaf: "\f2a4";
|
|
||||||
$fa-var-deafness: "\f2a4";
|
|
||||||
$fa-var-dedent: "\f03b";
|
$fa-var-dedent: "\f03b";
|
||||||
$fa-var-delicious: "\f1a5";
|
$fa-var-delicious: "\f1a5";
|
||||||
$fa-var-desktop: "\f108";
|
$fa-var-desktop: "\f108";
|
||||||
$fa-var-deviantart: "\f1bd";
|
$fa-var-deviantart: "\f1bd";
|
||||||
$fa-var-diamond: "\f219";
|
|
||||||
$fa-var-digg: "\f1a6";
|
$fa-var-digg: "\f1a6";
|
||||||
$fa-var-dollar: "\f155";
|
$fa-var-dollar: "\f155";
|
||||||
$fa-var-dot-circle-o: "\f192";
|
$fa-var-dot-circle-o: "\f192";
|
||||||
$fa-var-download: "\f019";
|
$fa-var-download: "\f019";
|
||||||
$fa-var-dribbble: "\f17d";
|
$fa-var-dribbble: "\f17d";
|
||||||
$fa-var-drivers-license: "\f2c2";
|
|
||||||
$fa-var-drivers-license-o: "\f2c3";
|
|
||||||
$fa-var-dropbox: "\f16b";
|
$fa-var-dropbox: "\f16b";
|
||||||
$fa-var-drupal: "\f1a9";
|
$fa-var-drupal: "\f1a9";
|
||||||
$fa-var-edge: "\f282";
|
|
||||||
$fa-var-edit: "\f044";
|
$fa-var-edit: "\f044";
|
||||||
$fa-var-eercast: "\f2da";
|
|
||||||
$fa-var-eject: "\f052";
|
$fa-var-eject: "\f052";
|
||||||
$fa-var-ellipsis-h: "\f141";
|
$fa-var-ellipsis-h: "\f141";
|
||||||
$fa-var-ellipsis-v: "\f142";
|
$fa-var-ellipsis-v: "\f142";
|
||||||
$fa-var-empire: "\f1d1";
|
$fa-var-empire: "\f1d1";
|
||||||
$fa-var-envelope: "\f0e0";
|
$fa-var-envelope: "\f0e0";
|
||||||
$fa-var-envelope-o: "\f003";
|
$fa-var-envelope-o: "\f003";
|
||||||
$fa-var-envelope-open: "\f2b6";
|
|
||||||
$fa-var-envelope-open-o: "\f2b7";
|
|
||||||
$fa-var-envelope-square: "\f199";
|
$fa-var-envelope-square: "\f199";
|
||||||
$fa-var-envira: "\f299";
|
|
||||||
$fa-var-eraser: "\f12d";
|
$fa-var-eraser: "\f12d";
|
||||||
$fa-var-etsy: "\f2d7";
|
|
||||||
$fa-var-eur: "\f153";
|
$fa-var-eur: "\f153";
|
||||||
$fa-var-euro: "\f153";
|
$fa-var-euro: "\f153";
|
||||||
$fa-var-exchange: "\f0ec";
|
$fa-var-exchange: "\f0ec";
|
||||||
|
@ -248,21 +185,16 @@ $fa-var-exclamation: "\f12a";
|
||||||
$fa-var-exclamation-circle: "\f06a";
|
$fa-var-exclamation-circle: "\f06a";
|
||||||
$fa-var-exclamation-triangle: "\f071";
|
$fa-var-exclamation-triangle: "\f071";
|
||||||
$fa-var-expand: "\f065";
|
$fa-var-expand: "\f065";
|
||||||
$fa-var-expeditedssl: "\f23e";
|
|
||||||
$fa-var-external-link: "\f08e";
|
$fa-var-external-link: "\f08e";
|
||||||
$fa-var-external-link-square: "\f14c";
|
$fa-var-external-link-square: "\f14c";
|
||||||
$fa-var-eye: "\f06e";
|
$fa-var-eye: "\f06e";
|
||||||
$fa-var-eye-slash: "\f070";
|
$fa-var-eye-slash: "\f070";
|
||||||
$fa-var-eyedropper: "\f1fb";
|
$fa-var-eyedropper: "\f1fb";
|
||||||
$fa-var-fa: "\f2b4";
|
|
||||||
$fa-var-facebook: "\f09a";
|
$fa-var-facebook: "\f09a";
|
||||||
$fa-var-facebook-f: "\f09a";
|
|
||||||
$fa-var-facebook-official: "\f230";
|
|
||||||
$fa-var-facebook-square: "\f082";
|
$fa-var-facebook-square: "\f082";
|
||||||
$fa-var-fast-backward: "\f049";
|
$fa-var-fast-backward: "\f049";
|
||||||
$fa-var-fast-forward: "\f050";
|
$fa-var-fast-forward: "\f050";
|
||||||
$fa-var-fax: "\f1ac";
|
$fa-var-fax: "\f1ac";
|
||||||
$fa-var-feed: "\f09e";
|
|
||||||
$fa-var-female: "\f182";
|
$fa-var-female: "\f182";
|
||||||
$fa-var-fighter-jet: "\f0fb";
|
$fa-var-fighter-jet: "\f0fb";
|
||||||
$fa-var-file: "\f15b";
|
$fa-var-file: "\f15b";
|
||||||
|
@ -288,8 +220,6 @@ $fa-var-film: "\f008";
|
||||||
$fa-var-filter: "\f0b0";
|
$fa-var-filter: "\f0b0";
|
||||||
$fa-var-fire: "\f06d";
|
$fa-var-fire: "\f06d";
|
||||||
$fa-var-fire-extinguisher: "\f134";
|
$fa-var-fire-extinguisher: "\f134";
|
||||||
$fa-var-firefox: "\f269";
|
|
||||||
$fa-var-first-order: "\f2b0";
|
|
||||||
$fa-var-flag: "\f024";
|
$fa-var-flag: "\f024";
|
||||||
$fa-var-flag-checkered: "\f11e";
|
$fa-var-flag-checkered: "\f11e";
|
||||||
$fa-var-flag-o: "\f11d";
|
$fa-var-flag-o: "\f11d";
|
||||||
|
@ -302,13 +232,8 @@ $fa-var-folder-o: "\f114";
|
||||||
$fa-var-folder-open: "\f07c";
|
$fa-var-folder-open: "\f07c";
|
||||||
$fa-var-folder-open-o: "\f115";
|
$fa-var-folder-open-o: "\f115";
|
||||||
$fa-var-font: "\f031";
|
$fa-var-font: "\f031";
|
||||||
$fa-var-font-awesome: "\f2b4";
|
|
||||||
$fa-var-fonticons: "\f280";
|
|
||||||
$fa-var-fort-awesome: "\f286";
|
|
||||||
$fa-var-forumbee: "\f211";
|
|
||||||
$fa-var-forward: "\f04e";
|
$fa-var-forward: "\f04e";
|
||||||
$fa-var-foursquare: "\f180";
|
$fa-var-foursquare: "\f180";
|
||||||
$fa-var-free-code-camp: "\f2c5";
|
|
||||||
$fa-var-frown-o: "\f119";
|
$fa-var-frown-o: "\f119";
|
||||||
$fa-var-futbol-o: "\f1e3";
|
$fa-var-futbol-o: "\f1e3";
|
||||||
$fa-var-gamepad: "\f11b";
|
$fa-var-gamepad: "\f11b";
|
||||||
|
@ -317,87 +242,45 @@ $fa-var-gbp: "\f154";
|
||||||
$fa-var-ge: "\f1d1";
|
$fa-var-ge: "\f1d1";
|
||||||
$fa-var-gear: "\f013";
|
$fa-var-gear: "\f013";
|
||||||
$fa-var-gears: "\f085";
|
$fa-var-gears: "\f085";
|
||||||
$fa-var-genderless: "\f22d";
|
|
||||||
$fa-var-get-pocket: "\f265";
|
|
||||||
$fa-var-gg: "\f260";
|
|
||||||
$fa-var-gg-circle: "\f261";
|
|
||||||
$fa-var-gift: "\f06b";
|
$fa-var-gift: "\f06b";
|
||||||
$fa-var-git: "\f1d3";
|
$fa-var-git: "\f1d3";
|
||||||
$fa-var-git-square: "\f1d2";
|
$fa-var-git-square: "\f1d2";
|
||||||
$fa-var-github: "\f09b";
|
$fa-var-github: "\f09b";
|
||||||
$fa-var-github-alt: "\f113";
|
$fa-var-github-alt: "\f113";
|
||||||
$fa-var-github-square: "\f092";
|
$fa-var-github-square: "\f092";
|
||||||
$fa-var-gitlab: "\f296";
|
|
||||||
$fa-var-gittip: "\f184";
|
$fa-var-gittip: "\f184";
|
||||||
$fa-var-glass: "\f000";
|
$fa-var-glass: "\f000";
|
||||||
$fa-var-glide: "\f2a5";
|
|
||||||
$fa-var-glide-g: "\f2a6";
|
|
||||||
$fa-var-globe: "\f0ac";
|
$fa-var-globe: "\f0ac";
|
||||||
$fa-var-google: "\f1a0";
|
$fa-var-google: "\f1a0";
|
||||||
$fa-var-google-plus: "\f0d5";
|
$fa-var-google-plus: "\f0d5";
|
||||||
$fa-var-google-plus-circle: "\f2b3";
|
|
||||||
$fa-var-google-plus-official: "\f2b3";
|
|
||||||
$fa-var-google-plus-square: "\f0d4";
|
$fa-var-google-plus-square: "\f0d4";
|
||||||
$fa-var-google-wallet: "\f1ee";
|
$fa-var-google-wallet: "\f1ee";
|
||||||
$fa-var-graduation-cap: "\f19d";
|
$fa-var-graduation-cap: "\f19d";
|
||||||
$fa-var-gratipay: "\f184";
|
|
||||||
$fa-var-grav: "\f2d6";
|
|
||||||
$fa-var-group: "\f0c0";
|
$fa-var-group: "\f0c0";
|
||||||
$fa-var-h-square: "\f0fd";
|
$fa-var-h-square: "\f0fd";
|
||||||
$fa-var-hacker-news: "\f1d4";
|
$fa-var-hacker-news: "\f1d4";
|
||||||
$fa-var-hand-grab-o: "\f255";
|
|
||||||
$fa-var-hand-lizard-o: "\f258";
|
|
||||||
$fa-var-hand-o-down: "\f0a7";
|
$fa-var-hand-o-down: "\f0a7";
|
||||||
$fa-var-hand-o-left: "\f0a5";
|
$fa-var-hand-o-left: "\f0a5";
|
||||||
$fa-var-hand-o-right: "\f0a4";
|
$fa-var-hand-o-right: "\f0a4";
|
||||||
$fa-var-hand-o-up: "\f0a6";
|
$fa-var-hand-o-up: "\f0a6";
|
||||||
$fa-var-hand-paper-o: "\f256";
|
|
||||||
$fa-var-hand-peace-o: "\f25b";
|
|
||||||
$fa-var-hand-pointer-o: "\f25a";
|
|
||||||
$fa-var-hand-rock-o: "\f255";
|
|
||||||
$fa-var-hand-scissors-o: "\f257";
|
|
||||||
$fa-var-hand-spock-o: "\f259";
|
|
||||||
$fa-var-hand-stop-o: "\f256";
|
|
||||||
$fa-var-handshake-o: "\f2b5";
|
|
||||||
$fa-var-hard-of-hearing: "\f2a4";
|
|
||||||
$fa-var-hashtag: "\f292";
|
|
||||||
$fa-var-hdd-o: "\f0a0";
|
$fa-var-hdd-o: "\f0a0";
|
||||||
$fa-var-header: "\f1dc";
|
$fa-var-header: "\f1dc";
|
||||||
$fa-var-headphones: "\f025";
|
$fa-var-headphones: "\f025";
|
||||||
$fa-var-heart: "\f004";
|
$fa-var-heart: "\f004";
|
||||||
$fa-var-heart-o: "\f08a";
|
$fa-var-heart-o: "\f08a";
|
||||||
$fa-var-heartbeat: "\f21e";
|
|
||||||
$fa-var-history: "\f1da";
|
$fa-var-history: "\f1da";
|
||||||
$fa-var-home: "\f015";
|
$fa-var-home: "\f015";
|
||||||
$fa-var-hospital-o: "\f0f8";
|
$fa-var-hospital-o: "\f0f8";
|
||||||
$fa-var-hotel: "\f236";
|
|
||||||
$fa-var-hourglass: "\f254";
|
|
||||||
$fa-var-hourglass-1: "\f251";
|
|
||||||
$fa-var-hourglass-2: "\f252";
|
|
||||||
$fa-var-hourglass-3: "\f253";
|
|
||||||
$fa-var-hourglass-end: "\f253";
|
|
||||||
$fa-var-hourglass-half: "\f252";
|
|
||||||
$fa-var-hourglass-o: "\f250";
|
|
||||||
$fa-var-hourglass-start: "\f251";
|
|
||||||
$fa-var-houzz: "\f27c";
|
|
||||||
$fa-var-html5: "\f13b";
|
$fa-var-html5: "\f13b";
|
||||||
$fa-var-i-cursor: "\f246";
|
|
||||||
$fa-var-id-badge: "\f2c1";
|
|
||||||
$fa-var-id-card: "\f2c2";
|
|
||||||
$fa-var-id-card-o: "\f2c3";
|
|
||||||
$fa-var-ils: "\f20b";
|
$fa-var-ils: "\f20b";
|
||||||
$fa-var-image: "\f03e";
|
$fa-var-image: "\f03e";
|
||||||
$fa-var-imdb: "\f2d8";
|
|
||||||
$fa-var-inbox: "\f01c";
|
$fa-var-inbox: "\f01c";
|
||||||
$fa-var-indent: "\f03c";
|
$fa-var-indent: "\f03c";
|
||||||
$fa-var-industry: "\f275";
|
|
||||||
$fa-var-info: "\f129";
|
$fa-var-info: "\f129";
|
||||||
$fa-var-info-circle: "\f05a";
|
$fa-var-info-circle: "\f05a";
|
||||||
$fa-var-inr: "\f156";
|
$fa-var-inr: "\f156";
|
||||||
$fa-var-instagram: "\f16d";
|
$fa-var-instagram: "\f16d";
|
||||||
$fa-var-institution: "\f19c";
|
$fa-var-institution: "\f19c";
|
||||||
$fa-var-internet-explorer: "\f26b";
|
|
||||||
$fa-var-intersex: "\f224";
|
|
||||||
$fa-var-ioxhost: "\f208";
|
$fa-var-ioxhost: "\f208";
|
||||||
$fa-var-italic: "\f033";
|
$fa-var-italic: "\f033";
|
||||||
$fa-var-joomla: "\f1aa";
|
$fa-var-joomla: "\f1aa";
|
||||||
|
@ -411,7 +294,6 @@ $fa-var-laptop: "\f109";
|
||||||
$fa-var-lastfm: "\f202";
|
$fa-var-lastfm: "\f202";
|
||||||
$fa-var-lastfm-square: "\f203";
|
$fa-var-lastfm-square: "\f203";
|
||||||
$fa-var-leaf: "\f06c";
|
$fa-var-leaf: "\f06c";
|
||||||
$fa-var-leanpub: "\f212";
|
|
||||||
$fa-var-legal: "\f0e3";
|
$fa-var-legal: "\f0e3";
|
||||||
$fa-var-lemon-o: "\f094";
|
$fa-var-lemon-o: "\f094";
|
||||||
$fa-var-level-down: "\f149";
|
$fa-var-level-down: "\f149";
|
||||||
|
@ -425,7 +307,6 @@ $fa-var-line-chart: "\f201";
|
||||||
$fa-var-link: "\f0c1";
|
$fa-var-link: "\f0c1";
|
||||||
$fa-var-linkedin: "\f0e1";
|
$fa-var-linkedin: "\f0e1";
|
||||||
$fa-var-linkedin-square: "\f08c";
|
$fa-var-linkedin-square: "\f08c";
|
||||||
$fa-var-linode: "\f2b8";
|
|
||||||
$fa-var-linux: "\f17c";
|
$fa-var-linux: "\f17c";
|
||||||
$fa-var-list: "\f03a";
|
$fa-var-list: "\f03a";
|
||||||
$fa-var-list-alt: "\f022";
|
$fa-var-list-alt: "\f022";
|
||||||
|
@ -437,58 +318,32 @@ $fa-var-long-arrow-down: "\f175";
|
||||||
$fa-var-long-arrow-left: "\f177";
|
$fa-var-long-arrow-left: "\f177";
|
||||||
$fa-var-long-arrow-right: "\f178";
|
$fa-var-long-arrow-right: "\f178";
|
||||||
$fa-var-long-arrow-up: "\f176";
|
$fa-var-long-arrow-up: "\f176";
|
||||||
$fa-var-low-vision: "\f2a8";
|
|
||||||
$fa-var-magic: "\f0d0";
|
$fa-var-magic: "\f0d0";
|
||||||
$fa-var-magnet: "\f076";
|
$fa-var-magnet: "\f076";
|
||||||
$fa-var-mail-forward: "\f064";
|
$fa-var-mail-forward: "\f064";
|
||||||
$fa-var-mail-reply: "\f112";
|
$fa-var-mail-reply: "\f112";
|
||||||
$fa-var-mail-reply-all: "\f122";
|
$fa-var-mail-reply-all: "\f122";
|
||||||
$fa-var-male: "\f183";
|
$fa-var-male: "\f183";
|
||||||
$fa-var-map: "\f279";
|
|
||||||
$fa-var-map-marker: "\f041";
|
$fa-var-map-marker: "\f041";
|
||||||
$fa-var-map-o: "\f278";
|
|
||||||
$fa-var-map-pin: "\f276";
|
|
||||||
$fa-var-map-signs: "\f277";
|
|
||||||
$fa-var-mars: "\f222";
|
|
||||||
$fa-var-mars-double: "\f227";
|
|
||||||
$fa-var-mars-stroke: "\f229";
|
|
||||||
$fa-var-mars-stroke-h: "\f22b";
|
|
||||||
$fa-var-mars-stroke-v: "\f22a";
|
|
||||||
$fa-var-maxcdn: "\f136";
|
$fa-var-maxcdn: "\f136";
|
||||||
$fa-var-meanpath: "\f20c";
|
$fa-var-meanpath: "\f20c";
|
||||||
$fa-var-medium: "\f23a";
|
|
||||||
$fa-var-medkit: "\f0fa";
|
$fa-var-medkit: "\f0fa";
|
||||||
$fa-var-meetup: "\f2e0";
|
|
||||||
$fa-var-meh-o: "\f11a";
|
$fa-var-meh-o: "\f11a";
|
||||||
$fa-var-mercury: "\f223";
|
|
||||||
$fa-var-microchip: "\f2db";
|
|
||||||
$fa-var-microphone: "\f130";
|
$fa-var-microphone: "\f130";
|
||||||
$fa-var-microphone-slash: "\f131";
|
$fa-var-microphone-slash: "\f131";
|
||||||
$fa-var-minus: "\f068";
|
$fa-var-minus: "\f068";
|
||||||
$fa-var-minus-circle: "\f056";
|
$fa-var-minus-circle: "\f056";
|
||||||
$fa-var-minus-square: "\f146";
|
$fa-var-minus-square: "\f146";
|
||||||
$fa-var-minus-square-o: "\f147";
|
$fa-var-minus-square-o: "\f147";
|
||||||
$fa-var-mixcloud: "\f289";
|
|
||||||
$fa-var-mobile: "\f10b";
|
$fa-var-mobile: "\f10b";
|
||||||
$fa-var-mobile-phone: "\f10b";
|
$fa-var-mobile-phone: "\f10b";
|
||||||
$fa-var-modx: "\f285";
|
|
||||||
$fa-var-money: "\f0d6";
|
$fa-var-money: "\f0d6";
|
||||||
$fa-var-moon-o: "\f186";
|
$fa-var-moon-o: "\f186";
|
||||||
$fa-var-mortar-board: "\f19d";
|
$fa-var-mortar-board: "\f19d";
|
||||||
$fa-var-motorcycle: "\f21c";
|
|
||||||
$fa-var-mouse-pointer: "\f245";
|
|
||||||
$fa-var-music: "\f001";
|
$fa-var-music: "\f001";
|
||||||
$fa-var-navicon: "\f0c9";
|
$fa-var-navicon: "\f0c9";
|
||||||
$fa-var-neuter: "\f22c";
|
|
||||||
$fa-var-newspaper-o: "\f1ea";
|
$fa-var-newspaper-o: "\f1ea";
|
||||||
$fa-var-object-group: "\f247";
|
|
||||||
$fa-var-object-ungroup: "\f248";
|
|
||||||
$fa-var-odnoklassniki: "\f263";
|
|
||||||
$fa-var-odnoklassniki-square: "\f264";
|
|
||||||
$fa-var-opencart: "\f23d";
|
|
||||||
$fa-var-openid: "\f19b";
|
$fa-var-openid: "\f19b";
|
||||||
$fa-var-opera: "\f26a";
|
|
||||||
$fa-var-optin-monster: "\f23c";
|
|
||||||
$fa-var-outdent: "\f03b";
|
$fa-var-outdent: "\f03b";
|
||||||
$fa-var-pagelines: "\f18c";
|
$fa-var-pagelines: "\f18c";
|
||||||
$fa-var-paint-brush: "\f1fc";
|
$fa-var-paint-brush: "\f1fc";
|
||||||
|
@ -498,24 +353,19 @@ $fa-var-paperclip: "\f0c6";
|
||||||
$fa-var-paragraph: "\f1dd";
|
$fa-var-paragraph: "\f1dd";
|
||||||
$fa-var-paste: "\f0ea";
|
$fa-var-paste: "\f0ea";
|
||||||
$fa-var-pause: "\f04c";
|
$fa-var-pause: "\f04c";
|
||||||
$fa-var-pause-circle: "\f28b";
|
|
||||||
$fa-var-pause-circle-o: "\f28c";
|
|
||||||
$fa-var-paw: "\f1b0";
|
$fa-var-paw: "\f1b0";
|
||||||
$fa-var-paypal: "\f1ed";
|
$fa-var-paypal: "\f1ed";
|
||||||
$fa-var-pencil: "\f040";
|
$fa-var-pencil: "\f040";
|
||||||
$fa-var-pencil-square: "\f14b";
|
$fa-var-pencil-square: "\f14b";
|
||||||
$fa-var-pencil-square-o: "\f044";
|
$fa-var-pencil-square-o: "\f044";
|
||||||
$fa-var-percent: "\f295";
|
|
||||||
$fa-var-phone: "\f095";
|
$fa-var-phone: "\f095";
|
||||||
$fa-var-phone-square: "\f098";
|
$fa-var-phone-square: "\f098";
|
||||||
$fa-var-photo: "\f03e";
|
$fa-var-photo: "\f03e";
|
||||||
$fa-var-picture-o: "\f03e";
|
$fa-var-picture-o: "\f03e";
|
||||||
$fa-var-pie-chart: "\f200";
|
$fa-var-pie-chart: "\f200";
|
||||||
$fa-var-pied-piper: "\f2ae";
|
$fa-var-pied-piper: "\f1a7";
|
||||||
$fa-var-pied-piper-alt: "\f1a8";
|
$fa-var-pied-piper-alt: "\f1a8";
|
||||||
$fa-var-pied-piper-pp: "\f1a7";
|
|
||||||
$fa-var-pinterest: "\f0d2";
|
$fa-var-pinterest: "\f0d2";
|
||||||
$fa-var-pinterest-p: "\f231";
|
|
||||||
$fa-var-pinterest-square: "\f0d3";
|
$fa-var-pinterest-square: "\f0d3";
|
||||||
$fa-var-plane: "\f072";
|
$fa-var-plane: "\f072";
|
||||||
$fa-var-play: "\f04b";
|
$fa-var-play: "\f04b";
|
||||||
|
@ -526,36 +376,28 @@ $fa-var-plus: "\f067";
|
||||||
$fa-var-plus-circle: "\f055";
|
$fa-var-plus-circle: "\f055";
|
||||||
$fa-var-plus-square: "\f0fe";
|
$fa-var-plus-square: "\f0fe";
|
||||||
$fa-var-plus-square-o: "\f196";
|
$fa-var-plus-square-o: "\f196";
|
||||||
$fa-var-podcast: "\f2ce";
|
|
||||||
$fa-var-power-off: "\f011";
|
$fa-var-power-off: "\f011";
|
||||||
$fa-var-print: "\f02f";
|
$fa-var-print: "\f02f";
|
||||||
$fa-var-product-hunt: "\f288";
|
|
||||||
$fa-var-puzzle-piece: "\f12e";
|
$fa-var-puzzle-piece: "\f12e";
|
||||||
$fa-var-qq: "\f1d6";
|
$fa-var-qq: "\f1d6";
|
||||||
$fa-var-qrcode: "\f029";
|
$fa-var-qrcode: "\f029";
|
||||||
$fa-var-question: "\f128";
|
$fa-var-question: "\f128";
|
||||||
$fa-var-question-circle: "\f059";
|
$fa-var-question-circle: "\f059";
|
||||||
$fa-var-question-circle-o: "\f29c";
|
|
||||||
$fa-var-quora: "\f2c4";
|
|
||||||
$fa-var-quote-left: "\f10d";
|
$fa-var-quote-left: "\f10d";
|
||||||
$fa-var-quote-right: "\f10e";
|
$fa-var-quote-right: "\f10e";
|
||||||
$fa-var-ra: "\f1d0";
|
$fa-var-ra: "\f1d0";
|
||||||
$fa-var-random: "\f074";
|
$fa-var-random: "\f074";
|
||||||
$fa-var-ravelry: "\f2d9";
|
|
||||||
$fa-var-rebel: "\f1d0";
|
$fa-var-rebel: "\f1d0";
|
||||||
$fa-var-recycle: "\f1b8";
|
$fa-var-recycle: "\f1b8";
|
||||||
$fa-var-reddit: "\f1a1";
|
$fa-var-reddit: "\f1a1";
|
||||||
$fa-var-reddit-alien: "\f281";
|
|
||||||
$fa-var-reddit-square: "\f1a2";
|
$fa-var-reddit-square: "\f1a2";
|
||||||
$fa-var-refresh: "\f021";
|
$fa-var-refresh: "\f021";
|
||||||
$fa-var-registered: "\f25d";
|
|
||||||
$fa-var-remove: "\f00d";
|
$fa-var-remove: "\f00d";
|
||||||
$fa-var-renren: "\f18b";
|
$fa-var-renren: "\f18b";
|
||||||
$fa-var-reorder: "\f0c9";
|
$fa-var-reorder: "\f0c9";
|
||||||
$fa-var-repeat: "\f01e";
|
$fa-var-repeat: "\f01e";
|
||||||
$fa-var-reply: "\f112";
|
$fa-var-reply: "\f112";
|
||||||
$fa-var-reply-all: "\f122";
|
$fa-var-reply-all: "\f122";
|
||||||
$fa-var-resistance: "\f1d0";
|
|
||||||
$fa-var-retweet: "\f079";
|
$fa-var-retweet: "\f079";
|
||||||
$fa-var-rmb: "\f157";
|
$fa-var-rmb: "\f157";
|
||||||
$fa-var-road: "\f018";
|
$fa-var-road: "\f018";
|
||||||
|
@ -568,18 +410,13 @@ $fa-var-rss-square: "\f143";
|
||||||
$fa-var-rub: "\f158";
|
$fa-var-rub: "\f158";
|
||||||
$fa-var-ruble: "\f158";
|
$fa-var-ruble: "\f158";
|
||||||
$fa-var-rupee: "\f156";
|
$fa-var-rupee: "\f156";
|
||||||
$fa-var-s15: "\f2cd";
|
|
||||||
$fa-var-safari: "\f267";
|
|
||||||
$fa-var-save: "\f0c7";
|
$fa-var-save: "\f0c7";
|
||||||
$fa-var-scissors: "\f0c4";
|
$fa-var-scissors: "\f0c4";
|
||||||
$fa-var-scribd: "\f28a";
|
|
||||||
$fa-var-search: "\f002";
|
$fa-var-search: "\f002";
|
||||||
$fa-var-search-minus: "\f010";
|
$fa-var-search-minus: "\f010";
|
||||||
$fa-var-search-plus: "\f00e";
|
$fa-var-search-plus: "\f00e";
|
||||||
$fa-var-sellsy: "\f213";
|
|
||||||
$fa-var-send: "\f1d8";
|
$fa-var-send: "\f1d8";
|
||||||
$fa-var-send-o: "\f1d9";
|
$fa-var-send-o: "\f1d9";
|
||||||
$fa-var-server: "\f233";
|
|
||||||
$fa-var-share: "\f064";
|
$fa-var-share: "\f064";
|
||||||
$fa-var-share-alt: "\f1e0";
|
$fa-var-share-alt: "\f1e0";
|
||||||
$fa-var-share-alt-square: "\f1e1";
|
$fa-var-share-alt-square: "\f1e1";
|
||||||
|
@ -588,29 +425,16 @@ $fa-var-share-square-o: "\f045";
|
||||||
$fa-var-shekel: "\f20b";
|
$fa-var-shekel: "\f20b";
|
||||||
$fa-var-sheqel: "\f20b";
|
$fa-var-sheqel: "\f20b";
|
||||||
$fa-var-shield: "\f132";
|
$fa-var-shield: "\f132";
|
||||||
$fa-var-ship: "\f21a";
|
|
||||||
$fa-var-shirtsinbulk: "\f214";
|
|
||||||
$fa-var-shopping-bag: "\f290";
|
|
||||||
$fa-var-shopping-basket: "\f291";
|
|
||||||
$fa-var-shopping-cart: "\f07a";
|
$fa-var-shopping-cart: "\f07a";
|
||||||
$fa-var-shower: "\f2cc";
|
|
||||||
$fa-var-sign-in: "\f090";
|
$fa-var-sign-in: "\f090";
|
||||||
$fa-var-sign-language: "\f2a7";
|
|
||||||
$fa-var-sign-out: "\f08b";
|
$fa-var-sign-out: "\f08b";
|
||||||
$fa-var-signal: "\f012";
|
$fa-var-signal: "\f012";
|
||||||
$fa-var-signing: "\f2a7";
|
|
||||||
$fa-var-simplybuilt: "\f215";
|
|
||||||
$fa-var-sitemap: "\f0e8";
|
$fa-var-sitemap: "\f0e8";
|
||||||
$fa-var-skyatlas: "\f216";
|
|
||||||
$fa-var-skype: "\f17e";
|
$fa-var-skype: "\f17e";
|
||||||
$fa-var-slack: "\f198";
|
$fa-var-slack: "\f198";
|
||||||
$fa-var-sliders: "\f1de";
|
$fa-var-sliders: "\f1de";
|
||||||
$fa-var-slideshare: "\f1e7";
|
$fa-var-slideshare: "\f1e7";
|
||||||
$fa-var-smile-o: "\f118";
|
$fa-var-smile-o: "\f118";
|
||||||
$fa-var-snapchat: "\f2ab";
|
|
||||||
$fa-var-snapchat-ghost: "\f2ac";
|
|
||||||
$fa-var-snapchat-square: "\f2ad";
|
|
||||||
$fa-var-snowflake-o: "\f2dc";
|
|
||||||
$fa-var-soccer-ball-o: "\f1e3";
|
$fa-var-soccer-ball-o: "\f1e3";
|
||||||
$fa-var-sort: "\f0dc";
|
$fa-var-sort: "\f0dc";
|
||||||
$fa-var-sort-alpha-asc: "\f15d";
|
$fa-var-sort-alpha-asc: "\f15d";
|
||||||
|
@ -643,20 +467,13 @@ $fa-var-steam-square: "\f1b7";
|
||||||
$fa-var-step-backward: "\f048";
|
$fa-var-step-backward: "\f048";
|
||||||
$fa-var-step-forward: "\f051";
|
$fa-var-step-forward: "\f051";
|
||||||
$fa-var-stethoscope: "\f0f1";
|
$fa-var-stethoscope: "\f0f1";
|
||||||
$fa-var-sticky-note: "\f249";
|
|
||||||
$fa-var-sticky-note-o: "\f24a";
|
|
||||||
$fa-var-stop: "\f04d";
|
$fa-var-stop: "\f04d";
|
||||||
$fa-var-stop-circle: "\f28d";
|
|
||||||
$fa-var-stop-circle-o: "\f28e";
|
|
||||||
$fa-var-street-view: "\f21d";
|
|
||||||
$fa-var-strikethrough: "\f0cc";
|
$fa-var-strikethrough: "\f0cc";
|
||||||
$fa-var-stumbleupon: "\f1a4";
|
$fa-var-stumbleupon: "\f1a4";
|
||||||
$fa-var-stumbleupon-circle: "\f1a3";
|
$fa-var-stumbleupon-circle: "\f1a3";
|
||||||
$fa-var-subscript: "\f12c";
|
$fa-var-subscript: "\f12c";
|
||||||
$fa-var-subway: "\f239";
|
|
||||||
$fa-var-suitcase: "\f0f2";
|
$fa-var-suitcase: "\f0f2";
|
||||||
$fa-var-sun-o: "\f185";
|
$fa-var-sun-o: "\f185";
|
||||||
$fa-var-superpowers: "\f2dd";
|
|
||||||
$fa-var-superscript: "\f12b";
|
$fa-var-superscript: "\f12b";
|
||||||
$fa-var-support: "\f1cd";
|
$fa-var-support: "\f1cd";
|
||||||
$fa-var-table: "\f0ce";
|
$fa-var-table: "\f0ce";
|
||||||
|
@ -666,8 +483,6 @@ $fa-var-tag: "\f02b";
|
||||||
$fa-var-tags: "\f02c";
|
$fa-var-tags: "\f02c";
|
||||||
$fa-var-tasks: "\f0ae";
|
$fa-var-tasks: "\f0ae";
|
||||||
$fa-var-taxi: "\f1ba";
|
$fa-var-taxi: "\f1ba";
|
||||||
$fa-var-telegram: "\f2c6";
|
|
||||||
$fa-var-television: "\f26c";
|
|
||||||
$fa-var-tencent-weibo: "\f1d5";
|
$fa-var-tencent-weibo: "\f1d5";
|
||||||
$fa-var-terminal: "\f120";
|
$fa-var-terminal: "\f120";
|
||||||
$fa-var-text-height: "\f034";
|
$fa-var-text-height: "\f034";
|
||||||
|
@ -675,18 +490,6 @@ $fa-var-text-width: "\f035";
|
||||||
$fa-var-th: "\f00a";
|
$fa-var-th: "\f00a";
|
||||||
$fa-var-th-large: "\f009";
|
$fa-var-th-large: "\f009";
|
||||||
$fa-var-th-list: "\f00b";
|
$fa-var-th-list: "\f00b";
|
||||||
$fa-var-themeisle: "\f2b2";
|
|
||||||
$fa-var-thermometer: "\f2c7";
|
|
||||||
$fa-var-thermometer-0: "\f2cb";
|
|
||||||
$fa-var-thermometer-1: "\f2ca";
|
|
||||||
$fa-var-thermometer-2: "\f2c9";
|
|
||||||
$fa-var-thermometer-3: "\f2c8";
|
|
||||||
$fa-var-thermometer-4: "\f2c7";
|
|
||||||
$fa-var-thermometer-empty: "\f2cb";
|
|
||||||
$fa-var-thermometer-full: "\f2c7";
|
|
||||||
$fa-var-thermometer-half: "\f2c9";
|
|
||||||
$fa-var-thermometer-quarter: "\f2ca";
|
|
||||||
$fa-var-thermometer-three-quarters: "\f2c8";
|
|
||||||
$fa-var-thumb-tack: "\f08d";
|
$fa-var-thumb-tack: "\f08d";
|
||||||
$fa-var-thumbs-down: "\f165";
|
$fa-var-thumbs-down: "\f165";
|
||||||
$fa-var-thumbs-o-down: "\f088";
|
$fa-var-thumbs-o-down: "\f088";
|
||||||
|
@ -696,8 +499,6 @@ $fa-var-ticket: "\f145";
|
||||||
$fa-var-times: "\f00d";
|
$fa-var-times: "\f00d";
|
||||||
$fa-var-times-circle: "\f057";
|
$fa-var-times-circle: "\f057";
|
||||||
$fa-var-times-circle-o: "\f05c";
|
$fa-var-times-circle-o: "\f05c";
|
||||||
$fa-var-times-rectangle: "\f2d3";
|
|
||||||
$fa-var-times-rectangle-o: "\f2d4";
|
|
||||||
$fa-var-tint: "\f043";
|
$fa-var-tint: "\f043";
|
||||||
$fa-var-toggle-down: "\f150";
|
$fa-var-toggle-down: "\f150";
|
||||||
$fa-var-toggle-left: "\f191";
|
$fa-var-toggle-left: "\f191";
|
||||||
|
@ -705,15 +506,10 @@ $fa-var-toggle-off: "\f204";
|
||||||
$fa-var-toggle-on: "\f205";
|
$fa-var-toggle-on: "\f205";
|
||||||
$fa-var-toggle-right: "\f152";
|
$fa-var-toggle-right: "\f152";
|
||||||
$fa-var-toggle-up: "\f151";
|
$fa-var-toggle-up: "\f151";
|
||||||
$fa-var-trademark: "\f25c";
|
|
||||||
$fa-var-train: "\f238";
|
|
||||||
$fa-var-transgender: "\f224";
|
|
||||||
$fa-var-transgender-alt: "\f225";
|
|
||||||
$fa-var-trash: "\f1f8";
|
$fa-var-trash: "\f1f8";
|
||||||
$fa-var-trash-o: "\f014";
|
$fa-var-trash-o: "\f014";
|
||||||
$fa-var-tree: "\f1bb";
|
$fa-var-tree: "\f1bb";
|
||||||
$fa-var-trello: "\f181";
|
$fa-var-trello: "\f181";
|
||||||
$fa-var-tripadvisor: "\f262";
|
|
||||||
$fa-var-trophy: "\f091";
|
$fa-var-trophy: "\f091";
|
||||||
$fa-var-truck: "\f0d1";
|
$fa-var-truck: "\f0d1";
|
||||||
$fa-var-try: "\f195";
|
$fa-var-try: "\f195";
|
||||||
|
@ -721,45 +517,26 @@ $fa-var-tty: "\f1e4";
|
||||||
$fa-var-tumblr: "\f173";
|
$fa-var-tumblr: "\f173";
|
||||||
$fa-var-tumblr-square: "\f174";
|
$fa-var-tumblr-square: "\f174";
|
||||||
$fa-var-turkish-lira: "\f195";
|
$fa-var-turkish-lira: "\f195";
|
||||||
$fa-var-tv: "\f26c";
|
|
||||||
$fa-var-twitch: "\f1e8";
|
$fa-var-twitch: "\f1e8";
|
||||||
$fa-var-twitter: "\f099";
|
$fa-var-twitter: "\f099";
|
||||||
$fa-var-twitter-square: "\f081";
|
$fa-var-twitter-square: "\f081";
|
||||||
$fa-var-umbrella: "\f0e9";
|
$fa-var-umbrella: "\f0e9";
|
||||||
$fa-var-underline: "\f0cd";
|
$fa-var-underline: "\f0cd";
|
||||||
$fa-var-undo: "\f0e2";
|
$fa-var-undo: "\f0e2";
|
||||||
$fa-var-universal-access: "\f29a";
|
|
||||||
$fa-var-university: "\f19c";
|
$fa-var-university: "\f19c";
|
||||||
$fa-var-unlink: "\f127";
|
$fa-var-unlink: "\f127";
|
||||||
$fa-var-unlock: "\f09c";
|
$fa-var-unlock: "\f09c";
|
||||||
$fa-var-unlock-alt: "\f13e";
|
$fa-var-unlock-alt: "\f13e";
|
||||||
$fa-var-unsorted: "\f0dc";
|
$fa-var-unsorted: "\f0dc";
|
||||||
$fa-var-upload: "\f093";
|
$fa-var-upload: "\f093";
|
||||||
$fa-var-usb: "\f287";
|
|
||||||
$fa-var-usd: "\f155";
|
$fa-var-usd: "\f155";
|
||||||
$fa-var-user: "\f007";
|
$fa-var-user: "\f007";
|
||||||
$fa-var-user-circle: "\f2bd";
|
|
||||||
$fa-var-user-circle-o: "\f2be";
|
|
||||||
$fa-var-user-md: "\f0f0";
|
$fa-var-user-md: "\f0f0";
|
||||||
$fa-var-user-o: "\f2c0";
|
|
||||||
$fa-var-user-plus: "\f234";
|
|
||||||
$fa-var-user-secret: "\f21b";
|
|
||||||
$fa-var-user-times: "\f235";
|
|
||||||
$fa-var-users: "\f0c0";
|
$fa-var-users: "\f0c0";
|
||||||
$fa-var-vcard: "\f2bb";
|
|
||||||
$fa-var-vcard-o: "\f2bc";
|
|
||||||
$fa-var-venus: "\f221";
|
|
||||||
$fa-var-venus-double: "\f226";
|
|
||||||
$fa-var-venus-mars: "\f228";
|
|
||||||
$fa-var-viacoin: "\f237";
|
|
||||||
$fa-var-viadeo: "\f2a9";
|
|
||||||
$fa-var-viadeo-square: "\f2aa";
|
|
||||||
$fa-var-video-camera: "\f03d";
|
$fa-var-video-camera: "\f03d";
|
||||||
$fa-var-vimeo: "\f27d";
|
|
||||||
$fa-var-vimeo-square: "\f194";
|
$fa-var-vimeo-square: "\f194";
|
||||||
$fa-var-vine: "\f1ca";
|
$fa-var-vine: "\f1ca";
|
||||||
$fa-var-vk: "\f189";
|
$fa-var-vk: "\f189";
|
||||||
$fa-var-volume-control-phone: "\f2a0";
|
|
||||||
$fa-var-volume-down: "\f027";
|
$fa-var-volume-down: "\f027";
|
||||||
$fa-var-volume-off: "\f026";
|
$fa-var-volume-off: "\f026";
|
||||||
$fa-var-volume-up: "\f028";
|
$fa-var-volume-up: "\f028";
|
||||||
|
@ -767,33 +544,17 @@ $fa-var-warning: "\f071";
|
||||||
$fa-var-wechat: "\f1d7";
|
$fa-var-wechat: "\f1d7";
|
||||||
$fa-var-weibo: "\f18a";
|
$fa-var-weibo: "\f18a";
|
||||||
$fa-var-weixin: "\f1d7";
|
$fa-var-weixin: "\f1d7";
|
||||||
$fa-var-whatsapp: "\f232";
|
|
||||||
$fa-var-wheelchair: "\f193";
|
$fa-var-wheelchair: "\f193";
|
||||||
$fa-var-wheelchair-alt: "\f29b";
|
|
||||||
$fa-var-wifi: "\f1eb";
|
$fa-var-wifi: "\f1eb";
|
||||||
$fa-var-wikipedia-w: "\f266";
|
|
||||||
$fa-var-window-close: "\f2d3";
|
|
||||||
$fa-var-window-close-o: "\f2d4";
|
|
||||||
$fa-var-window-maximize: "\f2d0";
|
|
||||||
$fa-var-window-minimize: "\f2d1";
|
|
||||||
$fa-var-window-restore: "\f2d2";
|
|
||||||
$fa-var-windows: "\f17a";
|
$fa-var-windows: "\f17a";
|
||||||
$fa-var-won: "\f159";
|
$fa-var-won: "\f159";
|
||||||
$fa-var-wordpress: "\f19a";
|
$fa-var-wordpress: "\f19a";
|
||||||
$fa-var-wpbeginner: "\f297";
|
|
||||||
$fa-var-wpexplorer: "\f2de";
|
|
||||||
$fa-var-wpforms: "\f298";
|
|
||||||
$fa-var-wrench: "\f0ad";
|
$fa-var-wrench: "\f0ad";
|
||||||
$fa-var-xing: "\f168";
|
$fa-var-xing: "\f168";
|
||||||
$fa-var-xing-square: "\f169";
|
$fa-var-xing-square: "\f169";
|
||||||
$fa-var-y-combinator: "\f23b";
|
|
||||||
$fa-var-y-combinator-square: "\f1d4";
|
|
||||||
$fa-var-yahoo: "\f19e";
|
$fa-var-yahoo: "\f19e";
|
||||||
$fa-var-yc: "\f23b";
|
|
||||||
$fa-var-yc-square: "\f1d4";
|
|
||||||
$fa-var-yelp: "\f1e9";
|
$fa-var-yelp: "\f1e9";
|
||||||
$fa-var-yen: "\f157";
|
$fa-var-yen: "\f157";
|
||||||
$fa-var-yoast: "\f2b1";
|
|
||||||
$fa-var-youtube: "\f167";
|
$fa-var-youtube: "\f167";
|
||||||
$fa-var-youtube-play: "\f16a";
|
$fa-var-youtube-play: "\f16a";
|
||||||
$fa-var-youtube-square: "\f166";
|
$fa-var-youtube-square: "\f166";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*!
|
/*!
|
||||||
* Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
|
* Font Awesome 4.2.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -11,8 +11,7 @@
|
||||||
@import "fixed-width";
|
@import "fixed-width";
|
||||||
@import "list";
|
@import "list";
|
||||||
@import "bordered-pulled";
|
@import "bordered-pulled";
|
||||||
@import "animated";
|
@import "spinning";
|
||||||
@import "rotated-flipped";
|
@import "rotated-flipped";
|
||||||
@import "stacked";
|
@import "stacked";
|
||||||
@import "icons";
|
@import "icons";
|
||||||
@import "screen-reader";
|
|
||||||
|
|
|
@ -1,236 +1,56 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: UTF-8 -*-
|
# -*- coding: UTF-8 -*-
|
||||||
# vim: expandtab sw=4 ts=4 sts=4:
|
# vim: expandtab sw=4 ts=4 sts=4:
|
||||||
|
#
|
||||||
# (C) 2003 - 2018 Michal Čihař <michal@cihar.com> - python-gammu
|
|
||||||
# (C) 2015 - 2021 Raspian France <raspbianfrance@gmail.com> - RaspianFrance/raspisms
|
|
||||||
# (C) 2022 - Orsiris de Jong <orsiris.dejong@netperfect.fr> - NetInvent SASU
|
|
||||||
|
|
||||||
|
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
|
|
||||||
|
|
||||||
__intname__ = "gammu_get_unread_sms.py"
|
|
||||||
__author__ = "Orsiris de Jong - <orsiris.dejong@netperfect.fr>"
|
|
||||||
__version__ = "2.0.2"
|
|
||||||
__build__ = "2022102501"
|
|
||||||
__compat__ = "python2.7+"
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
|
||||||
import gammu
|
import gammu
|
||||||
|
import sys
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
from logging.handlers import RotatingFileHandler
|
|
||||||
import tempfile
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
|
|
||||||
LOG_FILE = "/var/log/{}.log".format(__intname__)
|
def main():
|
||||||
_DEBUG = os.environ.get("_DEBUG", False)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def get_logger(log_file):
|
|
||||||
# We would normally use ofunctions.logger_utils here with logger_get_logger(), but let's keep no dependencies
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
filehandler = RotatingFileHandler(
|
|
||||||
log_file, mode="a", encoding="utf-8", maxBytes=1048576, backupCount=3
|
|
||||||
)
|
|
||||||
except OSError:
|
|
||||||
try:
|
|
||||||
temp_log_file = tempfile.gettempdir() + os.sep + __name__ + ".log"
|
|
||||||
filehandler = RotatingFileHandler(
|
|
||||||
temp_log_file,
|
|
||||||
mode="a",
|
|
||||||
encoding="utf-8",
|
|
||||||
maxBytes=1048576,
|
|
||||||
backupCount=3,
|
|
||||||
)
|
|
||||||
except OSError as exc:
|
|
||||||
print("Cannot create log file: %s" % exc.__str__())
|
|
||||||
filehandler = None
|
|
||||||
|
|
||||||
_logger = logging.getLogger()
|
|
||||||
if _DEBUG:
|
|
||||||
_logger.setLevel(logging.DEBUG)
|
|
||||||
else:
|
|
||||||
_logger.setLevel(logging.INFO)
|
|
||||||
|
|
||||||
formatter = logging.Formatter("%(asctime)s :: %(levelname)s :: %(message)s")
|
|
||||||
if filehandler:
|
|
||||||
filehandler.setFormatter(formatter)
|
|
||||||
_logger.addHandler(filehandler)
|
|
||||||
consolehandler = logging.StreamHandler()
|
|
||||||
consolehandler.setFormatter(formatter)
|
|
||||||
_logger.addHandler(consolehandler)
|
|
||||||
return _logger
|
|
||||||
except Exception as exc:
|
|
||||||
print("Cannot create logger instance: %s" % exc.__str__())
|
|
||||||
|
|
||||||
|
|
||||||
def get_gammu_version():
|
|
||||||
# Quite badly coded, i'd use command_runner but I try to not have dependencies here
|
|
||||||
try:
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
["LC_ALL=C gammu", "--version"], shell=True, stdout=subprocess.PIPE
|
|
||||||
)
|
|
||||||
stdout, _ = proc.communicate()
|
|
||||||
version = re.search(r"Gammu version ([0-9]+)\.([0-9]+)\.([0-9]+)", str(stdout))
|
|
||||||
# dont' bother to return version[0] since it's the whole match
|
|
||||||
return (int(version[1]), int(version[2]), int(version[3]))
|
|
||||||
except Exception as exc:
|
|
||||||
logger.error("Cannot get gammu version: %s" % exc.__str__())
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_gammu_handle(config_file):
|
|
||||||
state_machine = gammu.StateMachine()
|
state_machine = gammu.StateMachine()
|
||||||
|
|
||||||
if config_file:
|
if len(sys.argv) < 2:
|
||||||
state_machine.ReadConfig(Filename=config_file)
|
sys.exit(1)
|
||||||
else :
|
else :
|
||||||
state_machine.Readconfig()
|
state_machine.ReadConfig(Filename=sys.argv[1])
|
||||||
|
del sys.argv[1]
|
||||||
|
|
||||||
state_machine.Init()
|
state_machine.Init()
|
||||||
|
|
||||||
return state_machine
|
|
||||||
|
|
||||||
|
|
||||||
def load_sms_from_gammu(state_machine):
|
|
||||||
"""
|
|
||||||
The actual function that retrieves SMS via GAMMU from your modem / phone
|
|
||||||
Also concatenates multiple SMS into single long SMS
|
|
||||||
"""
|
|
||||||
status = state_machine.GetSMSStatus()
|
status = state_machine.GetSMSStatus()
|
||||||
|
|
||||||
remaining_sms = status["SIMUsed"] + status["PhoneUsed"] + status["TemplatesUsed"]
|
remain = status['SIMUsed'] + status['PhoneUsed'] + status['TemplatesUsed']
|
||||||
logger.debug("Found %s sms" % remaining_sms)
|
|
||||||
sms_list = []
|
start = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
is_first_message = True
|
while remain > 0:
|
||||||
while remaining_sms > 0:
|
if start:
|
||||||
if is_first_message:
|
sms = state_machine.GetNextSMS(Start=True, Folder=0)
|
||||||
sms = state_machine.GetNextSMS(Start=is_first_message, Folder=0)
|
start = False
|
||||||
is_first_message = False
|
|
||||||
else:
|
else:
|
||||||
sms = state_machine.GetNextSMS(Location=sms[0]["Location"], Folder=0)
|
sms = state_machine.GetNextSMS(
|
||||||
remaining_sms = remaining_sms - len(sms)
|
Location=sms[0]['Location'], Folder=0
|
||||||
sms_list.append(sms)
|
)
|
||||||
|
remain = remain - len(sms)
|
||||||
|
|
||||||
|
for m in sms :
|
||||||
|
if m['State'] != 'UnRead' :
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(json.dumps({
|
||||||
|
'number': m['Number'],
|
||||||
|
'at': str(m['DateTime']),
|
||||||
|
'status': m['State'],
|
||||||
|
'text': m['Text'],
|
||||||
|
}))
|
||||||
|
|
||||||
except gammu.ERR_EMPTY:
|
except gammu.ERR_EMPTY:
|
||||||
logger.debug("Finished reading all messages")
|
#do noting
|
||||||
|
return True
|
||||||
# Concat multiple SMS into list of sms that go together using LinkSMS
|
|
||||||
return gammu.LinkSMS(sms_list)
|
|
||||||
|
|
||||||
|
|
||||||
def render_sms_as_json(state_machine, sms_list, delete_sms, show_read_sms):
|
if __name__ == '__main__':
|
||||||
"""
|
main()
|
||||||
Provided sms_list is a list of lists of sms, eg
|
|
||||||
sms_list = [
|
|
||||||
[sms],
|
|
||||||
[sms1, sms2], # When two sms are in the same list, they form a long sms
|
|
||||||
[sms],
|
|
||||||
]
|
|
||||||
|
|
||||||
Concatenate long SMS from multiple sends and print them as JSON on stdout
|
|
||||||
"""
|
|
||||||
|
|
||||||
for sms in sms_list:
|
|
||||||
if sms[0]["State"] == "UnRead" or show_read_sms:
|
|
||||||
sms_text = ""
|
|
||||||
for to_concat_sms in sms:
|
|
||||||
sms_text += to_concat_sms["Text"]
|
|
||||||
print(
|
|
||||||
json.dumps(
|
|
||||||
{
|
|
||||||
"number": sms[0]["Number"],
|
|
||||||
"at": str(sms[0]["DateTime"]),
|
|
||||||
"status": sms[0]["State"],
|
|
||||||
"text": sms_text,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if delete_sms:
|
|
||||||
for to_concat_sms in sms:
|
|
||||||
try:
|
|
||||||
state_machine.DeleteSMS(
|
|
||||||
to_concat_sms["Folder"], to_concat_sms["Location"]
|
|
||||||
)
|
|
||||||
except Exception as exc:
|
|
||||||
logger.error("Cannot delete sms: %s" % exc.__str__())
|
|
||||||
|
|
||||||
|
|
||||||
def main(config_file, delete_sms, show_read):
|
|
||||||
# type: (bool, bool) -> None
|
|
||||||
logger.debug("Running gammu receiver with config {}".format(config_file))
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Mandatory modem config file
|
|
||||||
# config_file = sys.argv[1]
|
|
||||||
|
|
||||||
state_machine = get_gammu_handle(config_file)
|
|
||||||
|
|
||||||
sms_list = load_sms_from_gammu(state_machine)
|
|
||||||
render_sms_as_json(state_machine, sms_list, delete_sms, show_read)
|
|
||||||
|
|
||||||
except Exception as exc:
|
|
||||||
logger.error("Could not retrieve SMS from Gammu: %s" % exc.__str__())
|
|
||||||
logger.debug("Trace:", exc_info=True)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = ArgumentParser("Gammu SMS retriever")
|
|
||||||
parser.add_argument(
|
|
||||||
"gammu_config_file", type=str, nargs="?", help="Gammu config file"
|
|
||||||
)
|
|
||||||
parser.add_argument("--debug", action="store_true", help="Activate debugging")
|
|
||||||
parser.add_argument(
|
|
||||||
"-l",
|
|
||||||
"--log-file",
|
|
||||||
type=str,
|
|
||||||
dest="log_file",
|
|
||||||
default=None,
|
|
||||||
help="Optional path to log file, defaults to /var/log",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--delete", action="store_true", help="Delete messages after they've been read"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--show-read", action="store_true", help="Also show already read messages"
|
|
||||||
)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
config_file = args.gammu_config_file
|
|
||||||
|
|
||||||
if args.log_file:
|
|
||||||
LOG_FILE = args.log_file
|
|
||||||
|
|
||||||
if args.debug:
|
|
||||||
_DEBUG = args.debug
|
|
||||||
|
|
||||||
_logger = get_logger(LOG_FILE)
|
|
||||||
if _logger:
|
|
||||||
logger = _logger
|
|
||||||
|
|
||||||
delete = False
|
|
||||||
if args.delete:
|
|
||||||
# We need to check if we have gammu >= 1.42.0 since deleting sms with lower versions fail with:
|
|
||||||
# Cannot delete sms: {'Text': 'The type of memory is not available or has been disabled.', 'Where': 'DeleteSMS', 'Code': 81}
|
|
||||||
# see https://github.com/gammu/gammu/issues/460
|
|
||||||
try:
|
|
||||||
gammu_version = get_gammu_version()
|
|
||||||
if gammu_version[0] > 1 or (gammu_version[0] == 1 and gammu_version[1] >= 42):
|
|
||||||
delete = True
|
|
||||||
else:
|
|
||||||
logger.warning("Cannot delete SMS. You need gammu >= 1.42.0.")
|
|
||||||
except TypeError:
|
|
||||||
logger.warning("Cannot get gammu version. SMS Deleting might not work properly.")
|
|
||||||
|
|
||||||
show_read = args.show_read
|
|
||||||
main(config_file, delete, show_read)
|
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
"twilio/sdk": "^6.1",
|
"twilio/sdk": "^6.1",
|
||||||
"symfony/yaml": "^5.0",
|
"symfony/yaml": "^5.0",
|
||||||
"phpmailer/phpmailer": "^6.1",
|
"phpmailer/phpmailer": "^6.1",
|
||||||
"xantios/mimey": ">=2.1",
|
"ralouphie/mimey": "^2.1",
|
||||||
"kreait/firebase-php": "^5.14",
|
"kreait/firebase-php": "^5.14"
|
||||||
"benmorel/gsm-charset-converter": "^0.3.0"
|
},
|
||||||
|
"require-dev": {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
composer.phar
BIN
composer.phar
Binary file not shown.
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
namespace controllers\internals;
|
namespace controllers\internals;
|
||||||
|
|
||||||
use DateInterval;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to call the console scripts.
|
* Class to call the console scripts.
|
||||||
*/
|
*/
|
||||||
|
@ -214,46 +212,4 @@ use DateInterval;
|
||||||
$internal_quota = new \controllers\internals\Quota($bdd);
|
$internal_quota = new \controllers\internals\Quota($bdd);
|
||||||
$internal_quota->renew_quotas();
|
$internal_quota->renew_quotas();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Do some fake population renewal.
|
|
||||||
*/
|
|
||||||
public function f()
|
|
||||||
{
|
|
||||||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
|
||||||
$internal_sended = new \controllers\internals\Sended($bdd);
|
|
||||||
|
|
||||||
$destinations = ['+33612345678','+33612345679','+33612345680',];
|
|
||||||
$statuses = [\models\Sended::STATUS_DELIVERED, \models\Sended::STATUS_FAILED, \models\Sended::STATUS_UNKNOWN];
|
|
||||||
$day = new \DateTime();
|
|
||||||
$day->sub(new DateInterval('P30D'));
|
|
||||||
for ($i = 0; $i < 30; $i++)
|
|
||||||
{
|
|
||||||
$day->add(new DateInterval('P1D'));
|
|
||||||
$n = rand(0, 100);
|
|
||||||
for ($j = 0; $j < $n; $j++)
|
|
||||||
{
|
|
||||||
$id_user = 1;
|
|
||||||
$id_phone = rand(1, 2);
|
|
||||||
$destination = $destinations[array_rand($destinations)];
|
|
||||||
$status = $statuses[array_rand($statuses)];
|
|
||||||
$internal_sended->create(
|
|
||||||
$id_user,
|
|
||||||
$id_phone,
|
|
||||||
$day->format('Y-m-d H:i:s'),
|
|
||||||
"TEST N°$i:$j",
|
|
||||||
$destination,
|
|
||||||
uniqid(),
|
|
||||||
'adapters\TestAdapter',
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
[],
|
|
||||||
null,
|
|
||||||
$status,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,11 +141,8 @@ namespace controllers\internals;
|
||||||
$nb_insert = 0;
|
$nb_insert = 0;
|
||||||
|
|
||||||
$head = null;
|
$head = null;
|
||||||
$line_nb = 0;
|
|
||||||
while ($line = fgetcsv($file_handler))
|
while ($line = fgetcsv($file_handler))
|
||||||
{
|
{
|
||||||
$line_nb ++;
|
|
||||||
|
|
||||||
if (null === $head)
|
if (null === $head)
|
||||||
{
|
{
|
||||||
$head = $line;
|
$head = $line;
|
||||||
|
@ -163,7 +160,7 @@ namespace controllers\internals;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isset(array_keys($line)[0], array_keys($line)[1]))
|
if (!isset($line[array_keys($line)[0]], $line[array_keys($line)[1]]))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -188,16 +185,9 @@ namespace controllers\internals;
|
||||||
}
|
}
|
||||||
$data = json_encode($data);
|
$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
|
try
|
||||||
{
|
{
|
||||||
$success = $this->create($id_user, $line[array_keys($line)[1]], $contact_name, $data);
|
$success = $this->create($id_user, $line[array_keys($line)[1]], $line[array_keys($line)[0]], $data);
|
||||||
if ($success)
|
if ($success)
|
||||||
{
|
{
|
||||||
++$nb_insert;
|
++$nb_insert;
|
||||||
|
|
|
@ -73,6 +73,21 @@ namespace controllers\internals;
|
||||||
return $this->get_model()->insert($event);
|
return $this->get_model()->insert($event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets events for a type, since a date and eventually until a date (both included).
|
||||||
|
*
|
||||||
|
* @param int $id_user : User id
|
||||||
|
* @param string $type : Event type we want
|
||||||
|
* @param \DateTime $since : Date to get events since
|
||||||
|
* @param ?\DateTime $until (optional) : Date until wich we want events, if not specified no limit
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_events_by_type_and_date_for_user(int $id_user, string $type, \DateTime $since, ?\DateTime $until = null)
|
||||||
|
{
|
||||||
|
$this->get_model()->get_events_by_type_and_date_for_user($id_user, $type, $since, $until);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the model for the Controller.
|
* Get the model for the Controller.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -44,6 +44,11 @@ class ExpressionProvider implements ExpressionFunctionProviderInterface
|
||||||
return sprintf('isset(%1$s) && is_a(%1$s, \'DateTime\') && %1$s->format(\'m-d\') == (new \\DateTime())->format(\'m-d\')', $birthdate);
|
return sprintf('isset(%1$s) && is_a(%1$s, \'DateTime\') && %1$s->format(\'m-d\') == (new \\DateTime())->format(\'m-d\')', $birthdate);
|
||||||
}, function ($arguments, DateTime $birthdate)
|
}, function ($arguments, DateTime $birthdate)
|
||||||
{
|
{
|
||||||
|
if (!($birthdate ?? false))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return $birthdate->format('m-d') == (new DateTime())->format('m-d');
|
return $birthdate->format('m-d') == (new DateTime())->format('m-d');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
<?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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,7 +48,7 @@ class Media extends StandardController
|
||||||
|
|
||||||
if (!file_put_contents($new_file_path, 'a'))
|
if (!file_put_contents($new_file_path, 'a'))
|
||||||
{
|
{
|
||||||
throw new \Exception('Cannot write file ' . $new_file_path);
|
throw new \Exception('pute de merde');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rename($tmpfile_path, $new_file_path))
|
if (!rename($tmpfile_path, $new_file_path))
|
||||||
|
@ -56,6 +56,16 @@ class Media extends StandardController
|
||||||
throw new \Exception('Cannot create file ' . $new_file_path);
|
throw new \Exception('Cannot create file ' . $new_file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!chown($new_file_path, fileowner($user_path)))
|
||||||
|
{
|
||||||
|
throw new \Exception('Cannot give file ' . $new_file_path . ' to user : ' . fileowner($user_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chgrp($new_file_path, filegroup($user_path)))
|
||||||
|
{
|
||||||
|
throw new \Exception('Cannot give file ' . $new_file_path . ' to group : ' . filegroup($user_path));
|
||||||
|
}
|
||||||
|
|
||||||
if (!chmod($new_file_path, self::DEFAULT_CHMOD))
|
if (!chmod($new_file_path, self::DEFAULT_CHMOD))
|
||||||
{
|
{
|
||||||
throw new \Exception('Cannot give file ' . $new_file_path . ' rights : ' . self::DEFAULT_CHMOD);
|
throw new \Exception('Cannot give file ' . $new_file_path . ' rights : ' . self::DEFAULT_CHMOD);
|
||||||
|
|
|
@ -19,18 +19,6 @@ namespace controllers\internals;
|
||||||
|
|
||||||
protected $model;
|
protected $model;
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all phones for active users.
|
|
||||||
*
|
|
||||||
* @param int $id_user : user id
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function get_all_for_active_users()
|
|
||||||
{
|
|
||||||
return $this->get_model()->get_all_for_active_users();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all phones of a user.
|
* Return all phones of a user.
|
||||||
*
|
*
|
||||||
|
@ -44,15 +32,15 @@ namespace controllers\internals;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of phone limits
|
* Return a phone by his name.
|
||||||
*
|
*
|
||||||
* @param int $id_phone : Phone id
|
* @param string $name : Phone name
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function get_limits(int $id_phone)
|
public function get_by_name(string $name)
|
||||||
{
|
{
|
||||||
return $this->get_model()->get_limits($id_phone);
|
return $this->get_model()->get_by_name($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,46 +125,19 @@ namespace controllers\internals;
|
||||||
* @param string $name : The name of the phone
|
* @param string $name : The name of the phone
|
||||||
* @param string $adapter : The adapter to use the phone
|
* @param string $adapter : The adapter to use the phone
|
||||||
* @param string json $adapter_data : A JSON string representing adapter's data (for example credentials for an api)
|
* @param string json $adapter_data : A JSON string representing adapter's data (for example credentials for an api)
|
||||||
* @param int $priority : Priority with which to use phone to send SMS. Default 0.
|
|
||||||
* @param array $limits : An array of limits for this phone. Each limit must be an array with a key volume and a key startpoint
|
|
||||||
*
|
*
|
||||||
* @return bool|int : false on error, new id on success
|
* @return bool|int : false on error, new id on success
|
||||||
*/
|
*/
|
||||||
public function create(int $id_user, string $name, string $adapter, string $adapter_data, int $priority = 0, array $limits = [])
|
public function create(int $id_user, string $name, string $adapter, string $adapter_data)
|
||||||
{
|
{
|
||||||
$phone = [
|
$phone = [
|
||||||
'id_user' => $id_user,
|
'id_user' => $id_user,
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'priority' => $priority,
|
|
||||||
'adapter' => $adapter,
|
'adapter' => $adapter,
|
||||||
'adapter_data' => $adapter_data,
|
'adapter_data' => $adapter_data,
|
||||||
];
|
];
|
||||||
|
|
||||||
//Use transaction to garanty atomicity
|
return $this->get_model()->insert($phone);
|
||||||
$this->bdd->beginTransaction();
|
|
||||||
|
|
||||||
$new_phone_id = $this->get_model()->insert($phone);
|
|
||||||
if (!$new_phone_id)
|
|
||||||
{
|
|
||||||
$this->bdd->rollBack();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($limits as $limit)
|
|
||||||
{
|
|
||||||
$limit_id = $this->get_model()->insert_phone_limit($new_phone_id, $limit['volume'], $limit['startpoint']);
|
|
||||||
|
|
||||||
if (!$limit_id)
|
|
||||||
{
|
|
||||||
$this->bdd->rollBack();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$success = $this->bdd->commit();
|
|
||||||
return ($success ? $new_phone_id : false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -186,67 +147,20 @@ namespace controllers\internals;
|
||||||
* @param int $id : Phone id
|
* @param int $id : Phone id
|
||||||
* @param string $name : The name of the phone
|
* @param string $name : The name of the phone
|
||||||
* @param string $adapter : The adapter to use the phone
|
* @param string $adapter : The adapter to use the phone
|
||||||
* @param string json $adapter_data : A JSON string representing adapter's data (for example credentials for an api)
|
* @param array $adapter_data : An array of the data of the adapter (for example credentials for an api)
|
||||||
* @param int $priority : Priority with which to use phone to send SMS. Default 0.
|
|
||||||
* @param array $limits : An array of limits for this phone. Each limit must be an array with a key volume and a key startpoint
|
|
||||||
*
|
*
|
||||||
* @return bool : false on error, true on success
|
* @return bool : false on error, true on success
|
||||||
*/
|
*/
|
||||||
public function update_for_user(int $id_user, int $id, string $name, string $adapter, string $adapter_data, int $priority = 0, array $limits = []): bool
|
public function update_for_user(int $id_user, int $id, string $name, string $adapter, array $adapter_data): bool
|
||||||
{
|
{
|
||||||
$phone = [
|
$phone = [
|
||||||
'id_user' => $id_user,
|
'id_user' => $id_user,
|
||||||
'name' => $name,
|
'name' => $name,
|
||||||
'adapter' => $adapter,
|
'adapter' => $adapter,
|
||||||
'adapter_data' => $adapter_data,
|
'adapter_data' => json_encode($adapter_data),
|
||||||
'priority' => $priority,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
//Use transaction to garanty atomicity
|
return (bool) $this->get_model()->update_for_user($id_user, $id, $phone);
|
||||||
$this->bdd->beginTransaction();
|
|
||||||
|
|
||||||
$nb_delete = $this->get_model()->delete_phone_limits($id);
|
|
||||||
|
|
||||||
foreach ($limits as $limit)
|
|
||||||
{
|
|
||||||
$limit_id = $this->get_model()->insert_phone_limit($id, $limit['volume'], $limit['startpoint']);
|
|
||||||
|
|
||||||
if (!$limit_id)
|
|
||||||
{
|
|
||||||
$this->bdd->rollBack();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$nb_update = $this->get_model()->update_for_user($id_user, $id, $phone);
|
|
||||||
|
|
||||||
$success = $this->bdd->commit();
|
|
||||||
|
|
||||||
if (!$success)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($nb_update == 0 && count($limits) == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
<?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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classe des groups.
|
|
||||||
*/
|
|
||||||
class PhoneGroup extends StandardController
|
|
||||||
{
|
|
||||||
protected $model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new phone group for a user.
|
|
||||||
*
|
|
||||||
* @param int $id_user : user id
|
|
||||||
* @param stirng $name : Group name
|
|
||||||
* @param array $phones_ids : Ids of the phones of the group
|
|
||||||
*
|
|
||||||
* @return mixed bool|int : false on error, new group id
|
|
||||||
*/
|
|
||||||
public function create(int $id_user, string $name, array $phones_ids)
|
|
||||||
{
|
|
||||||
$group = [
|
|
||||||
'id_user' => $id_user,
|
|
||||||
'name' => $name,
|
|
||||||
];
|
|
||||||
|
|
||||||
$id_group = $this->get_model()->insert($group);
|
|
||||||
if (!$id_group)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$internal_phone = new Phone($this->bdd);
|
|
||||||
foreach ($phones_ids as $phone_id)
|
|
||||||
{
|
|
||||||
$phone = $internal_phone->get_for_user($id_user, $phone_id);
|
|
||||||
if (!$phone)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->get_model()->insert_phone_group_phone_relation($id_group, $phone_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
$internal_event = new Event($this->bdd);
|
|
||||||
$internal_event->create($id_user, 'PHONE_GROUP_ADD', 'Ajout phone group : ' . $name);
|
|
||||||
|
|
||||||
return $id_group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a phone group for a user.
|
|
||||||
*
|
|
||||||
* @param int $id_user : User id
|
|
||||||
* @param int $id_group : Group id
|
|
||||||
* @param stirng $name : Group name
|
|
||||||
* @param array $phones_ids : Ids of the phones of the group
|
|
||||||
*
|
|
||||||
* @return bool : False on error, true on success
|
|
||||||
*/
|
|
||||||
public function update_for_user(int $id_user, int $id_group, string $name, array $phones_ids)
|
|
||||||
{
|
|
||||||
$group = [
|
|
||||||
'name' => $name,
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = $this->get_model()->update_for_user($id_user, $id_group, $group);
|
|
||||||
|
|
||||||
$this->get_model()->delete_phone_group_phone_relations($id_group);
|
|
||||||
|
|
||||||
$internal_phone = new Phone($this->bdd);
|
|
||||||
$nb_phone_insert = 0;
|
|
||||||
foreach ($phones_ids as $phone_id)
|
|
||||||
{
|
|
||||||
$phone = $internal_phone->get_for_user($id_user, $phone_id);
|
|
||||||
if (!$phone)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->get_model()->insert_phone_group_phone_relation($id_group, $phone_id))
|
|
||||||
{
|
|
||||||
++$nb_phone_insert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$result && $nb_phone_insert !== \count($phones_ids))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a group by his name for a user.
|
|
||||||
*
|
|
||||||
* @param int $id_user : User id
|
|
||||||
* @param string $name : Group name
|
|
||||||
*
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get groups phones.
|
|
||||||
*
|
|
||||||
* @param int $id_group : Group id
|
|
||||||
*
|
|
||||||
* @return array : phones of the group
|
|
||||||
*/
|
|
||||||
public function get_phones($id_group)
|
|
||||||
{
|
|
||||||
return $this->get_model()->get_phones($id_group);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the model for the Controller.
|
|
||||||
*/
|
|
||||||
protected function get_model(): \models\PhoneGroup
|
|
||||||
{
|
|
||||||
$this->model = $this->model ?? new \models\PhoneGroup($this->bdd);
|
|
||||||
|
|
||||||
return $this->model;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
namespace controllers\internals;
|
namespace controllers\internals;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class Received extends StandardController
|
class Received extends StandardController
|
||||||
{
|
{
|
||||||
protected $model;
|
protected $model;
|
||||||
|
@ -90,6 +88,14 @@ use Exception;
|
||||||
return false;
|
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
|
//Link medias
|
||||||
$internal_media = new Media($this->bdd);
|
$internal_media = new Media($this->bdd);
|
||||||
foreach ($media_ids as $media_id)
|
foreach ($media_ids as $media_id)
|
||||||
|
@ -110,32 +116,6 @@ use Exception;
|
||||||
return false;
|
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;
|
return $id_received;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,8 @@ use Monolog\Logger;
|
||||||
* @param $at : Scheduled date to send
|
* @param $at : Scheduled date to send
|
||||||
* @param string $text : Text of the message
|
* @param string $text : Text of the message
|
||||||
* @param ?int $id_phone : Id of the phone to send message with, null by default
|
* @param ?int $id_phone : Id of the phone to send message with, null by default
|
||||||
* @param ?int $id_phone_group : Id of the phone group to send message with, null by default
|
|
||||||
* @param bool $flash : Is the sms a flash sms, by default false
|
* @param bool $flash : Is the sms a flash sms, by default false
|
||||||
* @param bool $mms : Is the sms a mms, by default false
|
* @param bool $mms : Is the sms a mms, by default false
|
||||||
* @param ?string $tag : A string tag to associate to sended SMS
|
|
||||||
* @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}']
|
* @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}']
|
||||||
* @param array $contacts_ids : Contact ids to send message to
|
* @param array $contacts_ids : Contact ids to send message to
|
||||||
* @param array $groups_ids : Group ids to send message to
|
* @param array $groups_ids : Group ids to send message to
|
||||||
|
@ -37,17 +35,15 @@ use Monolog\Logger;
|
||||||
*
|
*
|
||||||
* @return bool : false on error, new id on success
|
* @return bool : false on error, new id on success
|
||||||
*/
|
*/
|
||||||
public function create(int $id_user, $at, string $text, ?int $id_phone = null, ?int $id_phone_group = null, bool $flash = false, bool $mms = false, ?string $tag = null, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
public function create(int $id_user, $at, string $text, ?int $id_phone = null, bool $flash = false, bool $mms = false, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
||||||
{
|
{
|
||||||
$scheduled = [
|
$scheduled = [
|
||||||
'id_user' => $id_user,
|
'id_user' => $id_user,
|
||||||
'at' => $at,
|
'at' => $at,
|
||||||
'text' => $text,
|
'text' => $text,
|
||||||
'id_phone' => $id_phone,
|
'id_phone' => $id_phone,
|
||||||
'id_phone_group' => $id_phone_group,
|
|
||||||
'flash' => $flash,
|
'flash' => $flash,
|
||||||
'mms' => $mms,
|
'mms' => $mms,
|
||||||
'tag' => $tag,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if ('' === $text)
|
if ('' === $text)
|
||||||
|
@ -66,17 +62,6 @@ use Monolog\Logger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $id_phone_group)
|
|
||||||
{
|
|
||||||
$internal_phone_group = new PhoneGroup($this->bdd);
|
|
||||||
$find_phone_group = $internal_phone_group->get_for_user($id_user, $id_phone_group);
|
|
||||||
|
|
||||||
if (!$find_phone_group)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Use transaction to garanty atomicity
|
//Use transaction to garanty atomicity
|
||||||
$this->bdd->beginTransaction();
|
$this->bdd->beginTransaction();
|
||||||
|
|
||||||
|
@ -162,10 +147,8 @@ use Monolog\Logger;
|
||||||
* @param $at : Scheduled date to send
|
* @param $at : Scheduled date to send
|
||||||
* @param string $text : Text of the message
|
* @param string $text : Text of the message
|
||||||
* @param ?int $id_phone : Id of the phone to send message with, null by default
|
* @param ?int $id_phone : Id of the phone to send message with, null by default
|
||||||
* @param ?int $id_phone_group : Id of the phone group to send message with, null by default
|
|
||||||
* @param bool $flash : Is the sms a flash sms, by default false
|
* @param bool $flash : Is the sms a flash sms, by default false
|
||||||
* @param bool $mms : Is the sms a mms, by default false
|
* @param bool $mms : Is the sms a mms, by default false
|
||||||
* @param ?string $tag : A string tag to associate to sended SMS
|
|
||||||
* @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}']
|
* @param array $numbers : Array of numbers to send message to, a number is an array ['number' => '+33XXX', 'data' => '{"key":"value", ...}']
|
||||||
* @param array $contacts_ids : Contact ids to send message to
|
* @param array $contacts_ids : Contact ids to send message to
|
||||||
* @param array $groups_ids : Group ids to send message to
|
* @param array $groups_ids : Group ids to send message to
|
||||||
|
@ -174,17 +157,15 @@ use Monolog\Logger;
|
||||||
*
|
*
|
||||||
* @return bool : false on error, true on success
|
* @return bool : false on error, true on success
|
||||||
*/
|
*/
|
||||||
public function update_for_user(int $id_user, int $id_scheduled, $at, string $text, ?int $id_phone = null, ?int $id_phone_group = null, bool $flash = false, bool $mms = false, ?string $tag = null, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
public function update_for_user(int $id_user, int $id_scheduled, $at, string $text, ?string $id_phone = null, bool $flash = false, bool $mms = false, array $numbers = [], array $contacts_ids = [], array $groups_ids = [], array $conditional_group_ids = [], array $media_ids = [])
|
||||||
{
|
{
|
||||||
$scheduled = [
|
$scheduled = [
|
||||||
'id_user' => $id_user,
|
'id_user' => $id_user,
|
||||||
'at' => $at,
|
'at' => $at,
|
||||||
'text' => $text,
|
'text' => $text,
|
||||||
'id_phone' => $id_phone,
|
'id_phone' => $id_phone,
|
||||||
'id_phone_group' => $id_phone_group,
|
|
||||||
'mms' => $mms,
|
'mms' => $mms,
|
||||||
'flash' => $flash,
|
'flash' => $flash,
|
||||||
'tag' => $tag,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
if (null !== $id_phone)
|
if (null !== $id_phone)
|
||||||
|
@ -198,17 +179,6 @@ use Monolog\Logger;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null !== $id_phone_group)
|
|
||||||
{
|
|
||||||
$internal_phone_group = new PhoneGroup($this->bdd);
|
|
||||||
$find_phone_group = $internal_phone_group->get_for_user($id_user, $id_phone_group);
|
|
||||||
|
|
||||||
if (!$find_phone_group)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Ensure atomicity
|
//Ensure atomicity
|
||||||
$this->bdd->beginTransaction();
|
$this->bdd->beginTransaction();
|
||||||
|
|
||||||
|
@ -304,6 +274,236 @@ use Monolog\Logger;
|
||||||
return $this->get_model()->gets_after_date_for_number_and_user($id_user, $date, $number);
|
return $this->get_model()->gets_after_date_for_number_and_user($id_user, $date, $number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all messages to send and the number to use to send theme.
|
||||||
|
*
|
||||||
|
* @return array : List of smss to send at this time per scheduled id ['1' => [['id_scheduled', 'text', 'id_phone', 'destination', 'flash', 'mms', 'medias'], ...], ...]
|
||||||
|
*/
|
||||||
|
public function get_smss_to_send()
|
||||||
|
{
|
||||||
|
$smss_to_send_per_scheduled = [];
|
||||||
|
|
||||||
|
$internal_templating = new \controllers\internals\Templating();
|
||||||
|
$internal_setting = new \controllers\internals\Setting($this->bdd);
|
||||||
|
$internal_group = new \controllers\internals\Group($this->bdd);
|
||||||
|
$internal_conditional_group = new \controllers\internals\ConditionalGroup($this->bdd);
|
||||||
|
$internal_phone = new \controllers\internals\Phone($this->bdd);
|
||||||
|
$internal_smsstop = new \controllers\internals\SmsStop($this->bdd);
|
||||||
|
|
||||||
|
$users_smsstops = [];
|
||||||
|
$users_settings = [];
|
||||||
|
$users_phones = [];
|
||||||
|
$users_mms_phones = [];
|
||||||
|
|
||||||
|
$now = new \DateTime();
|
||||||
|
$now = $now->format('Y-m-d H:i:s');
|
||||||
|
$scheduleds = $this->get_model()->gets_before_date($now);
|
||||||
|
foreach ($scheduleds as $scheduled)
|
||||||
|
{
|
||||||
|
$smss_to_send_per_scheduled[$scheduled['id']] = [];
|
||||||
|
|
||||||
|
if (!isset($users_settings[$scheduled['id_user']]))
|
||||||
|
{
|
||||||
|
$users_settings[$scheduled['id_user']] = [];
|
||||||
|
|
||||||
|
$settings = $internal_setting->gets_for_user($scheduled['id_user']);
|
||||||
|
foreach ($settings as $name => $value)
|
||||||
|
{
|
||||||
|
$users_settings[$scheduled['id_user']][$name] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($users_smsstops[$scheduled['id_user']]) && $users_settings[$scheduled['id_user']]['smsstop'])
|
||||||
|
{
|
||||||
|
$users_smsstops[$scheduled['id_user']] = [];
|
||||||
|
|
||||||
|
$smsstops = $internal_smsstop->gets_for_user($scheduled['id_user']);
|
||||||
|
foreach ($smsstops as $smsstop)
|
||||||
|
{
|
||||||
|
$users_smsstops[$scheduled['id_user']][] = $smsstop['number'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($users_phones[$scheduled['id_user']]))
|
||||||
|
{
|
||||||
|
$phones = $internal_phone->gets_for_user($scheduled['id_user']);
|
||||||
|
$mms_phones = $internal_phone->gets_phone_supporting_mms_for_user($scheduled['id_user'], $internal_phone::MMS_SENDING);
|
||||||
|
$users_phones[$scheduled['id_user']] = $phones ?: [];
|
||||||
|
$users_mms_phones[$scheduled['id_user']] = $mms_phones ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add medias to mms
|
||||||
|
$scheduled['medias'] = [];
|
||||||
|
if ($scheduled['mms'])
|
||||||
|
{
|
||||||
|
$internal_media = new Media($this->bdd);
|
||||||
|
$scheduled['medias'] = $internal_media->gets_for_scheduled($scheduled['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$phone_to_use = null;
|
||||||
|
foreach ($users_phones[$scheduled['id_user']] as $phone)
|
||||||
|
{
|
||||||
|
if ($phone['id'] !== $scheduled['id_phone'])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$phone_to_use = $phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
|
||||||
|
//Add messages for numbers
|
||||||
|
$numbers = $this->get_numbers($scheduled['id']);
|
||||||
|
foreach ($numbers as $number)
|
||||||
|
{
|
||||||
|
if (null === $phone_to_use)
|
||||||
|
{
|
||||||
|
if ($scheduled['mms'] && count($users_mms_phones))
|
||||||
|
{
|
||||||
|
$rnd_key = array_rand($users_mms_phones[$scheduled['id_user']]);
|
||||||
|
$random_phone = $users_mms_phones[$scheduled['id_user']][$rnd_key];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$rnd_key = array_rand($users_phones[$scheduled['id_user']]);
|
||||||
|
$random_phone = $users_phones[$scheduled['id_user']][$rnd_key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = [
|
||||||
|
'id_user' => $scheduled['id_user'],
|
||||||
|
'id_scheduled' => $scheduled['id'],
|
||||||
|
'id_phone' => $phone_to_use['id'] ?? $random_phone['id'],
|
||||||
|
'destination' => $number['number'],
|
||||||
|
'flash' => $scheduled['flash'],
|
||||||
|
'mms' => $scheduled['mms'],
|
||||||
|
'medias' => $scheduled['medias'],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ((int) ($users_settings[$scheduled['id_user']]['templating'] ?? false))
|
||||||
|
{
|
||||||
|
$number['data'] = json_decode($number['data'] ?? '[]', true);
|
||||||
|
|
||||||
|
$metas = ['number' => $number['number']];
|
||||||
|
$data = ['contact' => $number['data'], 'contact_metas' => $metas];
|
||||||
|
|
||||||
|
$render = $internal_templating->render($scheduled['text'], $data);
|
||||||
|
|
||||||
|
if (!$render['success'])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message['text'] = $render['result'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$message['text'] = $scheduled['text'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages[] = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add messages for contacts
|
||||||
|
$contacts = $this->get_contacts($scheduled['id']);
|
||||||
|
|
||||||
|
$groups = $this->get_groups($scheduled['id']);
|
||||||
|
foreach ($groups as $group)
|
||||||
|
{
|
||||||
|
$contacts_to_add = $internal_group->get_contacts($group['id']);
|
||||||
|
$contacts = array_merge($contacts, $contacts_to_add);
|
||||||
|
}
|
||||||
|
|
||||||
|
$conditional_groups = $this->get_conditional_groups($scheduled['id']);
|
||||||
|
foreach ($conditional_groups as $conditional_group)
|
||||||
|
{
|
||||||
|
$contacts_to_add = $internal_conditional_group->get_contacts_for_condition_and_user($scheduled['id_user'], $conditional_group['condition']);
|
||||||
|
$contacts = array_merge($contacts, $contacts_to_add);
|
||||||
|
}
|
||||||
|
|
||||||
|
$added_contacts = [];
|
||||||
|
foreach ($contacts as $contact)
|
||||||
|
{
|
||||||
|
if ($added_contacts[$contact['id']] ?? false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$added_contacts[$contact['id']] = true;
|
||||||
|
|
||||||
|
if (null === $phone_to_use)
|
||||||
|
{
|
||||||
|
if ($scheduled['mms'] && count($users_mms_phones))
|
||||||
|
{
|
||||||
|
$rnd_key = array_rand($users_mms_phones[$scheduled['id_user']]);
|
||||||
|
$random_phone = $users_mms_phones[$scheduled['id_user']][$rnd_key];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$rnd_key = array_rand($users_phones[$scheduled['id_user']]);
|
||||||
|
$random_phone = $users_phones[$scheduled['id_user']][$rnd_key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = [
|
||||||
|
'id_user' => $scheduled['id_user'],
|
||||||
|
'id_scheduled' => $scheduled['id'],
|
||||||
|
'id_phone' => $phone_to_use['id'] ?? $random_phone['id'],
|
||||||
|
'destination' => $contact['number'],
|
||||||
|
'flash' => $scheduled['flash'],
|
||||||
|
'mms' => $scheduled['mms'],
|
||||||
|
'medias' => $scheduled['medias'],
|
||||||
|
];
|
||||||
|
|
||||||
|
if ((int) ($users_settings[$scheduled['id_user']]['templating'] ?? false))
|
||||||
|
{
|
||||||
|
$contact['data'] = json_decode($contact['data'], true);
|
||||||
|
|
||||||
|
//Add metas of contact by adding contact without data
|
||||||
|
$metas = $contact;
|
||||||
|
unset($metas['data'], $metas['id_user']);
|
||||||
|
|
||||||
|
$data = ['contact' => $contact['data'], 'contact_metas' => $metas];
|
||||||
|
|
||||||
|
$render = $internal_templating->render($scheduled['text'], $data);
|
||||||
|
|
||||||
|
if (!$render['success'])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$message['text'] = $render['result'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$message['text'] = $scheduled['text'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages[] = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($messages as $message)
|
||||||
|
{
|
||||||
|
//Remove empty messages
|
||||||
|
if ('' === trim($message['text']) && !$message['medias'])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove messages to smsstops numbers
|
||||||
|
if (($users_smsstops[$scheduled['id_user']] ?? false) && in_array($message['destination'], $users_smsstops[$scheduled['id_user']]))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$smss_to_send_per_scheduled[$scheduled['id']][] = $message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $smss_to_send_per_scheduled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a CSV file of numbers, potentially associated with datas.
|
* Parse a CSV file of numbers, potentially associated with datas.
|
||||||
*
|
*
|
||||||
|
@ -427,351 +627,4 @@ use Monolog\Logger;
|
||||||
|
|
||||||
return $this->model;
|
return $this->model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all messages to send and the number to use to send theme.
|
|
||||||
*
|
|
||||||
* @return array : List of smss to send at this time per scheduled id ['1' => [['id_scheduled', 'text', 'id_phone', 'destination', 'flash', 'mms', 'medias'], ...], ...]
|
|
||||||
*/
|
|
||||||
public function get_smss_to_send()
|
|
||||||
{
|
|
||||||
$sms_per_scheduled = [];
|
|
||||||
|
|
||||||
$internal_templating = new \controllers\internals\Templating();
|
|
||||||
$internal_setting = new \controllers\internals\Setting($this->bdd);
|
|
||||||
$internal_group = new \controllers\internals\Group($this->bdd);
|
|
||||||
$internal_conditional_group = new \controllers\internals\ConditionalGroup($this->bdd);
|
|
||||||
$internal_phone = new \controllers\internals\Phone($this->bdd);
|
|
||||||
$internal_phone_group = new \controllers\internals\PhoneGroup($this->bdd);
|
|
||||||
$internal_smsstop = new \controllers\internals\SmsStop($this->bdd);
|
|
||||||
$internal_sended = new \controllers\internals\Sended($this->bdd);
|
|
||||||
|
|
||||||
$users_smsstops = [];
|
|
||||||
$users_settings = [];
|
|
||||||
$users_phones = [];
|
|
||||||
$users_phone_groups = [];
|
|
||||||
$shortlink_cache = [];
|
|
||||||
|
|
||||||
$now = new \DateTime();
|
|
||||||
$now = $now->format('Y-m-d H:i:s');
|
|
||||||
$scheduleds = $this->get_model()->gets_before_date($now);
|
|
||||||
foreach ($scheduleds as $scheduled)
|
|
||||||
{
|
|
||||||
$id_scheduled = $scheduled['id'];
|
|
||||||
$id_user = $scheduled['id_user'];
|
|
||||||
|
|
||||||
$sms_per_scheduled[$id_scheduled] = [];
|
|
||||||
|
|
||||||
// Forge cache of data about users, sms stops, phones, etc.
|
|
||||||
if (!isset($users_settings[$id_user]))
|
|
||||||
{
|
|
||||||
$users_settings[$id_user] = [];
|
|
||||||
|
|
||||||
$settings = $internal_setting->gets_for_user($id_user);
|
|
||||||
foreach ($settings as $name => $value)
|
|
||||||
{
|
|
||||||
$users_settings[$id_user][$name] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($users_smsstops[$id_user]) && $users_settings[$id_user]['smsstop'])
|
|
||||||
{
|
|
||||||
$users_smsstops[$id_user] = [];
|
|
||||||
|
|
||||||
$smsstops = $internal_smsstop->gets_for_user($id_user);
|
|
||||||
foreach ($smsstops as $smsstop)
|
|
||||||
{
|
|
||||||
$users_smsstops[$id_user][] = $smsstop['number'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($users_phones[$id_user]))
|
|
||||||
{
|
|
||||||
$users_phones[$id_user] = [];
|
|
||||||
|
|
||||||
$phones = $internal_phone->gets_for_user($id_user);
|
|
||||||
foreach ($phones as &$phone)
|
|
||||||
{
|
|
||||||
$limits = $internal_phone->get_limits($phone['id']);
|
|
||||||
|
|
||||||
$remaining_volume = PHP_INT_MAX;
|
|
||||||
foreach ($limits as $limit)
|
|
||||||
{
|
|
||||||
$startpoint = new \DateTime($limit['startpoint']);
|
|
||||||
$consumed = $internal_sended->count_since_for_phone_and_user($id_user, $phone['id'], $startpoint);
|
|
||||||
$remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
$phone['remaining_volume'] = $remaining_volume;
|
|
||||||
$users_phones[$id_user][$phone['id']] = $phone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isset($users_phone_groups[$id_user]))
|
|
||||||
{
|
|
||||||
$users_phone_groups[$id_user] = [];
|
|
||||||
|
|
||||||
$phone_groups = $internal_phone_group->gets_for_user($id_user);
|
|
||||||
foreach ($phone_groups as $phone_group)
|
|
||||||
{
|
|
||||||
$phones = $internal_phone_group->get_phones($phone_group['id']);
|
|
||||||
$phone_group['phones'] = [];
|
|
||||||
foreach ($phones as $phone)
|
|
||||||
{
|
|
||||||
$phone_group['phones'][] = $phone['id'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$users_phone_groups[$id_user][$phone_group['id']] = $phone_group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Add medias to mms
|
|
||||||
$scheduled['medias'] = [];
|
|
||||||
if ($scheduled['mms'])
|
|
||||||
{
|
|
||||||
$internal_media = new Media($this->bdd);
|
|
||||||
$scheduled['medias'] = $internal_media->gets_for_scheduled($id_scheduled);
|
|
||||||
}
|
|
||||||
|
|
||||||
$phone_to_use = null;
|
|
||||||
if ($scheduled['id_phone'])
|
|
||||||
{
|
|
||||||
$phone_to_use = $users_phones[$id_user][$scheduled['id_phone']] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$phone_group_to_use = null;
|
|
||||||
if ($scheduled['id_phone_group'])
|
|
||||||
{
|
|
||||||
$phone_group_to_use = $users_phone_groups[$id_user][$scheduled['id_phone_group']] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// We turn all contacts, groups and conditional groups into just contacts
|
|
||||||
$contacts = $this->get_contacts($id_scheduled);
|
|
||||||
|
|
||||||
$groups = $this->get_groups($id_scheduled);
|
|
||||||
foreach ($groups as $group)
|
|
||||||
{
|
|
||||||
$contacts_to_add = $internal_group->get_contacts($group['id']);
|
|
||||||
$contacts = array_merge($contacts, $contacts_to_add);
|
|
||||||
}
|
|
||||||
|
|
||||||
$conditional_groups = $this->get_conditional_groups($id_scheduled);
|
|
||||||
foreach ($conditional_groups as $conditional_group)
|
|
||||||
{
|
|
||||||
$contacts_to_add = $internal_conditional_group->get_contacts_for_condition_and_user($id_user, $conditional_group['condition']);
|
|
||||||
$contacts = array_merge($contacts, $contacts_to_add);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// We turn all numbers and contacts into simple targets with number, data and meta so we can forge all messages from onlye one data source
|
|
||||||
$targets = [];
|
|
||||||
|
|
||||||
$numbers = $this->get_numbers($id_scheduled);
|
|
||||||
foreach ($numbers as $number)
|
|
||||||
{
|
|
||||||
$metas = ['number' => $number['number']];
|
|
||||||
$targets[] = [
|
|
||||||
'number' => $number['number'],
|
|
||||||
'data' => $number['data'],
|
|
||||||
'metas' => $metas,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($contacts as $contact)
|
|
||||||
{
|
|
||||||
$metas = $contact;
|
|
||||||
unset($metas['data'], $metas['id_user']);
|
|
||||||
|
|
||||||
$targets[] = [
|
|
||||||
'number' => $contact['number'],
|
|
||||||
'data' => $contact['data'],
|
|
||||||
'metas' => $metas,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Pass on all targets to deduplicate destinations, remove number in sms stops, etc.
|
|
||||||
$used_destinations = [];
|
|
||||||
foreach ($targets as $key => $target)
|
|
||||||
{
|
|
||||||
if (in_array($target['number'], $used_destinations))
|
|
||||||
{
|
|
||||||
unset($targets[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
|
|
||||||
$used_destinations[] = $target['number'];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Finally, we forge all messages and select phone to use
|
|
||||||
foreach ($targets as $target)
|
|
||||||
{
|
|
||||||
// Forge message if templating enable
|
|
||||||
$text = $scheduled['text'];
|
|
||||||
if ((int) ($users_settings[$id_user]['templating'] ?? false)) // Cast to int because it is more reliable than bool on strings
|
|
||||||
{
|
|
||||||
$target['data'] = json_decode($target['data'], true);
|
|
||||||
$data = ['contact' => $target['data'], 'contact_metas' => $target['metas']];
|
|
||||||
|
|
||||||
$render = $internal_templating->render($scheduled['text'], $data);
|
|
||||||
|
|
||||||
if (!$render['success'])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$text = $render['result'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore empty messages
|
|
||||||
if ('' === trim($text) && !$scheduled['medias'])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we must force GSM 7 alphabet
|
|
||||||
if ((int) ($users_settings[$id_user]['force_gsm_alphabet'] ?? false))
|
|
||||||
{
|
|
||||||
$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 :
|
|
||||||
1 - If sms is a mms, try to use mms phone if any available. If mms phone available use mms phone, else use default.
|
|
||||||
2 - In group of phones, keep only phones with remaining volume. If no phones with remaining volume, use all phones instead.
|
|
||||||
3 - Groupe keeped phones by priority get group with biggest priority.
|
|
||||||
4 - Get a random phone in this group.
|
|
||||||
5 - If their is no phone matching, keep phone at null so sender will directly mark it as failed
|
|
||||||
*/
|
|
||||||
$random_phone = null;
|
|
||||||
if (null === $phone_to_use)
|
|
||||||
{
|
|
||||||
$phones_subset = $users_phones[$id_user];
|
|
||||||
|
|
||||||
if ($phone_group_to_use)
|
|
||||||
{
|
|
||||||
$phones_subset = array_filter($phones_subset, function ($phone) use ($phone_group_to_use) {
|
|
||||||
return in_array($phone['id'], $phone_group_to_use['phones']);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scheduled['mms'])
|
|
||||||
{
|
|
||||||
$mms_only = array_filter($phones_subset, function ($phone) {
|
|
||||||
return $phone['adapter']::meta_support_mms_sending();
|
|
||||||
});
|
|
||||||
|
|
||||||
$phones_subset = $mms_only ?: $phones_subset;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep only available phones
|
|
||||||
$remaining_volume_phones = array_filter($phones_subset, function ($phone) {
|
|
||||||
return $phone['status'] == \models\Phone::STATUS_AVAILABLE;
|
|
||||||
});
|
|
||||||
$phones_subset = $remaining_volume_phones ?: $phones_subset;
|
|
||||||
|
|
||||||
|
|
||||||
// Keep only phones with remaining volume
|
|
||||||
if ((int) ($users_settings[$id_user]['phone_limit'] ?? false))
|
|
||||||
{
|
|
||||||
$remaining_volume_phones = array_filter($phones_subset, function ($phone) {
|
|
||||||
return $phone['remaining_volume'] > 0;
|
|
||||||
});
|
|
||||||
$phones_subset = $remaining_volume_phones ?: $phones_subset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((int) ($users_settings[$id_user]['phone_priority'] ?? false))
|
|
||||||
{
|
|
||||||
$max_priority_phones = [];
|
|
||||||
$max_priority = PHP_INT_MIN;
|
|
||||||
foreach ($phones_subset as $phone)
|
|
||||||
{
|
|
||||||
if ($phone['priority'] < $max_priority)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
elseif ($phone['priority'] == $max_priority)
|
|
||||||
{
|
|
||||||
$max_priority_phones[] = $phone;
|
|
||||||
}
|
|
||||||
elseif ($phone['priority'] > $max_priority)
|
|
||||||
{
|
|
||||||
$max_priority_phones = [$phone];
|
|
||||||
$max_priority = $phone['priority'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$phones_subset = $max_priority_phones;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($phones_subset)
|
|
||||||
{
|
|
||||||
$random_phone = $phones_subset[array_rand($phones_subset)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This should only happen if the user try to send a message without any phone in his account, then we simply ignore.
|
|
||||||
if (!$random_phone && !$phone_to_use)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$id_phone = $phone_to_use['id'] ?? $random_phone['id'];
|
|
||||||
$sms_per_scheduled[$id_scheduled][] = [
|
|
||||||
'id_user' => $id_user,
|
|
||||||
'id_scheduled' => $id_scheduled,
|
|
||||||
'id_phone' => $id_phone,
|
|
||||||
'destination' => $target['number'],
|
|
||||||
'flash' => $scheduled['flash'],
|
|
||||||
'mms' => $scheduled['mms'],
|
|
||||||
'tag' => $scheduled['tag'],
|
|
||||||
'medias' => $scheduled['medias'],
|
|
||||||
'text' => $text,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Consume one sms from remaining volume of phone
|
|
||||||
$users_phones[$id_user][$id_phone]['remaining_volume'] --;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sms_per_scheduled;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
namespace controllers\internals;
|
namespace controllers\internals;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class Sended extends StandardController
|
class Sended extends StandardController
|
||||||
{
|
{
|
||||||
protected $model;
|
protected $model;
|
||||||
|
@ -46,14 +44,13 @@ use Exception;
|
||||||
* @param string $adapter : Name of the adapter service used to send the message
|
* @param string $adapter : Name of the adapter service used to send the message
|
||||||
* @param bool $flash : Is the sms a flash
|
* @param bool $flash : Is the sms a flash
|
||||||
* @param bool $mms : Is the sms a MMS. By default false.
|
* @param bool $mms : Is the sms a MMS. By default false.
|
||||||
* @param ?string $tag : A string tag to associate to sended SMS
|
|
||||||
* @param array $medias : Array of medias to link to the MMS
|
* @param array $medias : Array of medias to link to the MMS
|
||||||
* @param ?int $originating_scheduled : Id of the scheduled message that was responsible for sending this message. By default null.
|
* @param ?int $originating_scheduled : Id of the scheduled message that was responsible for sending this message. By default null.
|
||||||
* @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN
|
* @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN
|
||||||
*
|
*
|
||||||
* @return mixed : false on error, new sended id else
|
* @return mixed : false on error, new sended id else
|
||||||
*/
|
*/
|
||||||
public function create(int $id_user, int $id_phone, $at, string $text, string $destination, string $uid, string $adapter, bool $flash = false, bool $mms = false, ?string $tag = null, array $medias = [], ?int $originating_scheduled = null, ?string $status = \models\Sended::STATUS_UNKNOWN)
|
public function create(int $id_user, int $id_phone, $at, string $text, string $destination, string $uid, string $adapter, bool $flash = false, bool $mms = false, array $medias = [], ?int $originating_scheduled = null, ?string $status = \models\Sended::STATUS_UNKNOWN)
|
||||||
{
|
{
|
||||||
$sended = [
|
$sended = [
|
||||||
'id_user' => $id_user,
|
'id_user' => $id_user,
|
||||||
|
@ -65,7 +62,6 @@ use Exception;
|
||||||
'adapter' => $adapter,
|
'adapter' => $adapter,
|
||||||
'flash' => $flash,
|
'flash' => $flash,
|
||||||
'mms' => $mms,
|
'mms' => $mms,
|
||||||
'tag' => $tag,
|
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
'originating_scheduled' => $originating_scheduled,
|
'originating_scheduled' => $originating_scheduled,
|
||||||
];
|
];
|
||||||
|
@ -183,22 +179,6 @@ use Exception;
|
||||||
return $this->get_model()->get_by_uid_and_adapter_for_user($id_user, $uid, $adapter);
|
return $this->get_model()->get_by_uid_and_adapter_for_user($id_user, $uid, $adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get number of sended SMS since a date for a phone
|
|
||||||
*
|
|
||||||
* @param int $id_user : User id
|
|
||||||
* @param int $id_phone : Phone id we want the number of sended message for
|
|
||||||
* @param ?\DateTime $since : Date since which we want sended number. Default to null.
|
|
||||||
* @param ?\DateTime $before : Date up to which we want sended number. Default to null.
|
|
||||||
* @param ?string $tag_like : Tag to filter sms by, this is not a = but a LIKE operator
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function count_since_for_phone_and_user(int $id_user, int $id_phone, ?\DateTime $since, ?\DateTime $before = null, ?string $tag_like = null): int
|
|
||||||
{
|
|
||||||
return $this->get_model()->count_since_for_phone_and_user($id_user, $id_phone, $since, $before, $tag_like);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of sended SMS for every date since a date for a specific user.
|
* Get number of sended SMS for every date since a date for a specific user.
|
||||||
*
|
*
|
||||||
|
@ -207,9 +187,17 @@ use Exception;
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function count_by_day_and_status_since_for_user(int $id_user, $date)
|
public function count_by_day_since_for_user(int $id_user, $date)
|
||||||
{
|
{
|
||||||
return $this->get_model()->count_by_day_and_status_since_for_user($id_user, $date);
|
$counts_by_day = $this->get_model()->count_by_day_since_for_user($id_user, $date);
|
||||||
|
$return = [];
|
||||||
|
|
||||||
|
foreach ($counts_by_day as $count_by_day)
|
||||||
|
{
|
||||||
|
$return[$count_by_day['at_ymd']] = $count_by_day['nb'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,7 +222,6 @@ use Exception;
|
||||||
* @param $text : Text of the message
|
* @param $text : Text of the message
|
||||||
* @param string $destination : Number of the receiver
|
* @param string $destination : Number of the receiver
|
||||||
* @param bool $flash : Is the sms a flash. By default false.
|
* @param bool $flash : Is the sms a flash. By default false.
|
||||||
* @param ?string $tag : A string tag to associate to sended SMS
|
|
||||||
* @param bool $mms : Is the sms a MMS. By default false.
|
* @param bool $mms : Is the sms a MMS. By default false.
|
||||||
* @param array $medias : Array of medias to link to the MMS
|
* @param array $medias : Array of medias to link to the MMS
|
||||||
* @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN
|
* @param string $status : Status of a the sms. By default \models\Sended::STATUS_UNKNOWN
|
||||||
|
@ -245,15 +232,23 @@ use Exception;
|
||||||
* ?string 'error_message' => null if success, error message else
|
* ?string 'error_message' => null if success, error message else
|
||||||
* ]
|
* ]
|
||||||
*/
|
*/
|
||||||
public function send(\adapters\AdapterInterface $adapter, int $id_user, int $id_phone, string $text, string $destination, bool $flash = false, bool $mms = false, ?string $tag = null, array $medias = [], $originating_scheduled = null, string $status = \models\Sended::STATUS_UNKNOWN): array
|
public function send(\adapters\AdapterInterface $adapter, int $id_user, int $id_phone, string $text, string $destination, bool $flash = false, bool $mms = false, array $medias = [], $originating_scheduled = null, string $status = \models\Sended::STATUS_UNKNOWN): array
|
||||||
{
|
{
|
||||||
$return = [
|
$return = [
|
||||||
'error' => false,
|
'error' => false,
|
||||||
'error_message' => null,
|
'error_message' => null,
|
||||||
];
|
];
|
||||||
|
|
||||||
$internal_setting = new Setting();
|
//If we reached our max quota, do not send the message
|
||||||
$user_settings = $internal_setting->gets_for_user($id_user);
|
$internal_quota = new Quota($this->bdd);
|
||||||
|
$nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require
|
||||||
|
if (!$internal_quota->has_enough_credit($id_user, $nb_credits))
|
||||||
|
{
|
||||||
|
$return['error'] = false;
|
||||||
|
$return['error_message'] = 'Not enough credit to send message.';
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
$at = (new \DateTime())->format('Y-m-d H:i:s');
|
$at = (new \DateTime())->format('Y-m-d H:i:s');
|
||||||
$media_uris = [];
|
$media_uris = [];
|
||||||
|
@ -277,71 +272,16 @@ use Exception;
|
||||||
$text .= "\n" . join(' - ', $media_urls);
|
$text .= "\n" . join(' - ', $media_urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//If we reached our max quota, do not send the message
|
|
||||||
$internal_quota = new Quota($this->bdd);
|
|
||||||
$nb_credits = $internal_quota::compute_credits_for_message($text); //Calculate how much credit the message require
|
|
||||||
if (!$internal_quota->has_enough_credit($id_user, $nb_credits))
|
|
||||||
{
|
|
||||||
throw new Exception('Not enough credit to send message.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this phone status indicate it is not available
|
|
||||||
$internal_phone = new Phone($this->bdd);
|
|
||||||
$phone = $internal_phone->get_for_user($id_user, $id_phone);
|
|
||||||
if (!$phone || $phone['status'] != \models\Phone::STATUS_AVAILABLE)
|
|
||||||
{
|
|
||||||
throw new Exception('Invalid phone status : ' . $phone['status']);
|
|
||||||
}
|
|
||||||
|
|
||||||
//If we reached limit for this phone and phone limits are enabled, do not send the message
|
|
||||||
if ((int) ($user_settings['phone_limit'] ?? false))
|
|
||||||
{
|
|
||||||
$limits = $internal_phone->get_limits($id_phone);
|
|
||||||
|
|
||||||
$remaining_volume = PHP_INT_MAX;
|
|
||||||
foreach ($limits as $limit)
|
|
||||||
{
|
|
||||||
$startpoint = new \DateTime($limit['startpoint']);
|
|
||||||
$consumed = $this->count_since_for_phone_and_user($id_user, $id_phone, $startpoint);
|
|
||||||
$remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($remaining_volume < 1)
|
|
||||||
{
|
|
||||||
throw new Exception('Phone send limit have been reached.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $adapter->send($destination, $text, $flash, $mms, $media_uris);
|
$response = $adapter->send($destination, $text, $flash, $mms, $media_uris);
|
||||||
|
|
||||||
if ($response['error'])
|
if ($response['error'])
|
||||||
{
|
|
||||||
throw new Exception($response['error_message']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$uid = $response['uid'];
|
|
||||||
$status = \models\Sended::STATUS_UNKNOWN;
|
|
||||||
|
|
||||||
// If send with success, consume credit
|
|
||||||
$internal_quota->consume_credit($id_user, $nb_credits);
|
|
||||||
}
|
|
||||||
catch (Exception $e)
|
|
||||||
{
|
{
|
||||||
$return['error'] = true;
|
$return['error'] = true;
|
||||||
$return['error_message'] = $e->getMessage();
|
$return['error_message'] = $response['error_message'];
|
||||||
|
|
||||||
$status = \models\Sended::STATUS_FAILED;
|
$status = \models\Sended::STATUS_FAILED;
|
||||||
|
$sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $response['uid'] ?? uniqid(), $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status);
|
||||||
|
|
||||||
return $return;
|
$sended = [
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
$uid = $uid ?? uniqid();
|
|
||||||
$sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $uid, $adapter->meta_classname(), $flash, $mms, $tag, $medias, $originating_scheduled, $status);
|
|
||||||
|
|
||||||
$webhook_body = [
|
|
||||||
'id' => $sended_id,
|
'id' => $sended_id,
|
||||||
'at' => $at,
|
'at' => $at,
|
||||||
'status' => $status,
|
'status' => $status,
|
||||||
|
@ -354,10 +294,31 @@ use Exception;
|
||||||
];
|
];
|
||||||
|
|
||||||
$internal_webhook = new Webhook($this->bdd);
|
$internal_webhook = new Webhook($this->bdd);
|
||||||
$internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $webhook_body);
|
$internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $sended);
|
||||||
|
|
||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$internal_quota->consume_credit($id_user, $nb_credits);
|
||||||
|
|
||||||
|
$sended_id = $this->create($id_user, $id_phone, $at, $text, $destination, $response['uid'] ?? uniqid(), $adapter->meta_classname(), $flash, $mms, $medias, $originating_scheduled, $status);
|
||||||
|
|
||||||
|
$sended = [
|
||||||
|
'id' => $sended_id,
|
||||||
|
'at' => $at,
|
||||||
|
'status' => $status,
|
||||||
|
'text' => $text,
|
||||||
|
'destination' => $destination,
|
||||||
|
'origin' => $id_phone,
|
||||||
|
'mms' => $mms,
|
||||||
|
'medias' => $medias,
|
||||||
|
'originating_scheduled' => $originating_scheduled,
|
||||||
|
];
|
||||||
|
|
||||||
|
$internal_webhook = new Webhook($this->bdd);
|
||||||
|
$internal_webhook->trigger($id_user, \models\Webhook::TYPE_SEND_SMS, $sended);
|
||||||
|
|
||||||
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -35,18 +35,6 @@ namespace controllers\internals;
|
||||||
return $settings_array;
|
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.
|
* Update a setting by his name and user id.
|
||||||
*
|
*
|
||||||
|
|
|
@ -73,8 +73,7 @@ namespace controllers\internals;
|
||||||
*/
|
*/
|
||||||
public function check_for_stop(string $str)
|
public function check_for_stop(string $str)
|
||||||
{
|
{
|
||||||
$str = trim(mb_strtolower($str));
|
return 'stop' == trim(mb_strtolower($str));
|
||||||
return 'stop' == $str || 'stop sms' == $str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
namespace controllers\internals;
|
namespace controllers\internals;
|
||||||
|
|
||||||
use BenMorel\GsmCharsetConverter\Converter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some tools frequently used.
|
* Some tools frequently used.
|
||||||
* Not a standard controller as it's not linked to a model in any way.
|
* Not a standard controller as it's not linked to a model in any way.
|
||||||
|
@ -85,22 +83,6 @@ use BenMorel\GsmCharsetConverter\Converter;
|
||||||
return '<a href="' . self::s($url, false, true, false) . '">' . self::s($number_format, false, true, false) . '</a>';
|
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.
|
* Cette fonction fait la correspondance entre un type d'evenement et une icone font awesome.
|
||||||
*
|
*
|
||||||
|
@ -183,24 +165,6 @@ use BenMorel\GsmCharsetConverter\Converter;
|
||||||
return $objectDate && $objectDate->format($format) === $date;
|
return $objectDate && $objectDate->format($format) === $date;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a relative format date (see https://www.php.net/manual/en/datetime.formats.relative.php) is valid.
|
|
||||||
*
|
|
||||||
* @param string $date : Relative date
|
|
||||||
*
|
|
||||||
* @return bool : True if valid, false else
|
|
||||||
*/
|
|
||||||
public static function validate_relative_date($date)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$d = new \DateTime($date);
|
|
||||||
} catch (\Throwable $th) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a sting represent a valid PHP period for creating an interval.
|
* Check if a sting represent a valid PHP period for creating an interval.
|
||||||
*
|
*
|
||||||
|
@ -430,17 +394,4 @@ use BenMorel\GsmCharsetConverter\Converter;
|
||||||
|
|
||||||
return "{$scheme}{$user}{$pass}{$host}{$port}{$path}{$query}{$fragment}";
|
return "{$scheme}{$user}{$pass}{$host}{$port}{$path}{$query}{$fragment}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transform an UTF-8 string into a valid GSM 7 string (GSM 03.38), remplacing invalid chars with best equivalent whenever possible
|
|
||||||
*
|
|
||||||
* @param string $text : Input text to convert into gsm string
|
|
||||||
* @return string : An UTF-8 string with GSM alphabet only
|
|
||||||
*/
|
|
||||||
public static function convert_to_gsm0338(string $text): string
|
|
||||||
{
|
|
||||||
$converter = new Converter();
|
|
||||||
return $converter->cleanUpUtf8String($text, true, '?');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,10 +137,10 @@ class Webhook extends StandardController
|
||||||
|
|
||||||
$error_code = null;
|
$error_code = null;
|
||||||
$queue = msg_get_queue(QUEUE_ID_WEBHOOK);
|
$queue = msg_get_queue(QUEUE_ID_WEBHOOK);
|
||||||
msg_send($queue, QUEUE_TYPE_WEBHOOK, $message, true, true, $error_code);
|
$success = msg_send($queue, QUEUE_TYPE_WEBHOOK, $message, true, true, $error_code);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return (bool) $success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -49,7 +49,6 @@ namespace controllers\publics;
|
||||||
|
|
||||||
private $internal_user;
|
private $internal_user;
|
||||||
private $internal_phone;
|
private $internal_phone;
|
||||||
private $internal_phone_group;
|
|
||||||
private $internal_received;
|
private $internal_received;
|
||||||
private $internal_sended;
|
private $internal_sended;
|
||||||
private $internal_scheduled;
|
private $internal_scheduled;
|
||||||
|
@ -73,7 +72,6 @@ namespace controllers\publics;
|
||||||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
||||||
$this->internal_user = new \controllers\internals\User($bdd);
|
$this->internal_user = new \controllers\internals\User($bdd);
|
||||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
||||||
$this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd);
|
|
||||||
$this->internal_received = new \controllers\internals\Received($bdd);
|
$this->internal_received = new \controllers\internals\Received($bdd);
|
||||||
$this->internal_sended = new \controllers\internals\Sended($bdd);
|
$this->internal_sended = new \controllers\internals\Sended($bdd);
|
||||||
$this->internal_scheduled = new \controllers\internals\Scheduled($bdd);
|
$this->internal_scheduled = new \controllers\internals\Scheduled($bdd);
|
||||||
|
@ -120,14 +118,14 @@ namespace controllers\publics;
|
||||||
/**
|
/**
|
||||||
* List all entries of a certain type for the current user, sorted by id.
|
* List all entries of a certain type for the current user, sorted by id.
|
||||||
*
|
*
|
||||||
* @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'phone_group', 'media']
|
* @param string $entry_type : Type of entries we want to list ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'media']
|
||||||
* @param int $page : Pagination number, Default = 0. Group of 25 results.
|
* @param int $page : Pagination number, Default = 0. Group of 25 results.
|
||||||
*
|
*
|
||||||
* @return : List of entries
|
* @return : List of entries
|
||||||
*/
|
*/
|
||||||
public function get_entries(string $entry_type, int $page = 0)
|
public function get_entries(string $entry_type, int $page = 0)
|
||||||
{
|
{
|
||||||
$entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'phone_group', 'media'];
|
$entry_types = ['sended', 'received', 'scheduled', 'contact', 'group', 'conditional_group', 'phone', 'media'];
|
||||||
|
|
||||||
if (!\in_array($entry_type, $entry_types, true))
|
if (!\in_array($entry_type, $entry_types, true))
|
||||||
{
|
{
|
||||||
|
@ -193,26 +191,6 @@ namespace controllers\publics;
|
||||||
unset($entries[$key]['adapter_data']);
|
unset($entries[$key]['adapter_data']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Special case for phone group we must add phones because its a join
|
|
||||||
elseif ('phone_group' === $entry_type)
|
|
||||||
{
|
|
||||||
foreach ($entries as $key => $entry)
|
|
||||||
{
|
|
||||||
$phones = $this->internal_phone_group->get_phones($entry['id']);
|
|
||||||
// Hide meta data of phones if needed
|
|
||||||
foreach ($phones as &$phone)
|
|
||||||
{
|
|
||||||
if (!$phone['adapter']::meta_hide_data())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
unset($phone['adapter_data']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$entries[$key]['phones'] = $phones;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$return = self::DEFAULT_RETURN;
|
$return = self::DEFAULT_RETURN;
|
||||||
$return['response'] = $entries;
|
$return['response'] = $entries;
|
||||||
|
@ -232,84 +210,14 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return info about volume of sms sended for a period
|
|
||||||
*
|
|
||||||
* @param ?string $_POST['start'] : Date from which to get sms volume, format Y-m-d H:i:s. Default to null.
|
|
||||||
* @param ?string $_POST['end'] : Date up to which to get sms volume, format Y-m-d H:i:s. Default to null.
|
|
||||||
* @param ?string $_POST['tag'] : Tag to filter SMS by. If set, only sended sms with a matching tag will be counted. Default to null.
|
|
||||||
*
|
|
||||||
* @return : List of entries
|
|
||||||
*/
|
|
||||||
public function get_usage()
|
|
||||||
{
|
|
||||||
$start = $_GET['start'] ?? null;
|
|
||||||
$end = $_GET['end'] ?? null;
|
|
||||||
$tag = $_GET['tag'] ?? null;
|
|
||||||
|
|
||||||
$return = self::DEFAULT_RETURN;
|
|
||||||
|
|
||||||
if ($start)
|
|
||||||
{
|
|
||||||
if (!\controllers\internals\Tool::validate_date($start, 'Y-m-d H:i:s'))
|
|
||||||
{
|
|
||||||
$return = self::DEFAULT_RETURN;
|
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
|
||||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'start must be a date of format "Y-m-d H:i:s".';
|
|
||||||
$this->auto_http_code(false);
|
|
||||||
|
|
||||||
return $this->json($return);
|
|
||||||
}
|
|
||||||
|
|
||||||
$start = new \DateTime($start);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($end)
|
|
||||||
{
|
|
||||||
if (!\controllers\internals\Tool::validate_date($end, 'Y-m-d H:i:s'))
|
|
||||||
{
|
|
||||||
$return = self::DEFAULT_RETURN;
|
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
|
||||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'end must be a date of format "Y-m-d H:i:s".';
|
|
||||||
$this->auto_http_code(false);
|
|
||||||
|
|
||||||
return $this->json($return);
|
|
||||||
}
|
|
||||||
|
|
||||||
$end = new \DateTime($end);
|
|
||||||
}
|
|
||||||
|
|
||||||
$total_sended = 0;
|
|
||||||
$phones_volumes = [];
|
|
||||||
|
|
||||||
$phones = $this->internal_phone->gets_for_user($this->user['id']);
|
|
||||||
foreach ($phones as $phone)
|
|
||||||
{
|
|
||||||
$nb_sended = $this->internal_sended->count_since_for_phone_and_user($this->user['id'], $phone['id'], $start, $end, $tag);
|
|
||||||
$total_sended += $nb_sended;
|
|
||||||
$phones_volumes[$phone['id']] = $nb_sended;
|
|
||||||
}
|
|
||||||
|
|
||||||
$return['response'] = [
|
|
||||||
'total' => $total_sended,
|
|
||||||
'phones_volumes' => $phones_volumes,
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->auto_http_code(true);
|
|
||||||
|
|
||||||
return $this->json($return);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a message to be send.
|
* Schedule a message to be send.
|
||||||
*
|
*
|
||||||
* @param string $_POST['at'] : Date to send message at format Y-m-d H:i:s
|
* @param string $_POST['at'] : Date to send message at format Y-m-d H:i:s
|
||||||
* @param string $_POST['text'] : Text of the message to send
|
* @param string $_POST['text'] : Text of the message to send
|
||||||
* @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null and id_phone_group null, use a random phone
|
* @param string $_POST['id_phone'] : Default null. Id of phone to send the message from. If null use a random phone
|
||||||
* @param string $_POST['id_phone_group'] : Default null. Id of phone group to send the message from. If null abd id_phone null, use a random phone
|
|
||||||
* @param string $_POST['flash'] : Default false. Is the sms a flash sms.
|
* @param string $_POST['flash'] : Default false. Is the sms a flash sms.
|
||||||
* @param string $_POST['mms'] : Default false. Is the sms a mms.
|
* @param string $_POST['mms'] : Default false. Is the sms a mms.
|
||||||
* @param string $_POST['tag'] : Default null. Tag to associate to every sms of the campaign.
|
|
||||||
* @param string $_POST['numbers'] : Array of numbers to send message to
|
* @param string $_POST['numbers'] : Array of numbers to send message to
|
||||||
* @param string $_POST['contacts'] : Array of ids of contacts to send message to
|
* @param string $_POST['contacts'] : Array of ids of contacts to send message to
|
||||||
* @param string $_POST['groups'] : Array of ids of groups to send message to
|
* @param string $_POST['groups'] : Array of ids of groups to send message to
|
||||||
|
@ -323,10 +231,8 @@ namespace controllers\publics;
|
||||||
$at = $_POST['at'] ?? false;
|
$at = $_POST['at'] ?? false;
|
||||||
$text = $_POST['text'] ?? false;
|
$text = $_POST['text'] ?? false;
|
||||||
$id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone'];
|
$id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone'];
|
||||||
$id_phone_group = empty($_POST['id_phone_group']) ? null : $_POST['id_phone_group'];
|
|
||||||
$flash = (bool) ($_POST['flash'] ?? false);
|
$flash = (bool) ($_POST['flash'] ?? false);
|
||||||
$mms = (bool) ($_POST['mms'] ?? false);
|
$mms = (bool) ($_POST['mms'] ?? false);
|
||||||
$tag = $_POST['tag'] ?? null;
|
|
||||||
$numbers = $_POST['numbers'] ?? [];
|
$numbers = $_POST['numbers'] ?? [];
|
||||||
$contacts = $_POST['contacts'] ?? [];
|
$contacts = $_POST['contacts'] ?? [];
|
||||||
$groups = $_POST['groups'] ?? [];
|
$groups = $_POST['groups'] ?? [];
|
||||||
|
@ -426,7 +332,7 @@ namespace controllers\publics;
|
||||||
$at = (string) $at;
|
$at = (string) $at;
|
||||||
$text = (string) $text;
|
$text = (string) $text;
|
||||||
|
|
||||||
if ($mms && !(int)($this->user['settings']['mms'] ?? false))
|
if (($this->user['settings']['mms'] ?? false) && $mms)
|
||||||
{
|
{
|
||||||
$return = self::DEFAULT_RETURN;
|
$return = self::DEFAULT_RETURN;
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||||
|
@ -511,16 +417,6 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($id_phone && $id_phone_group)
|
|
||||||
{
|
|
||||||
$return = self::DEFAULT_RETURN;
|
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
|
||||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone, id_phone_group : You must specify at most one of id_phone or id_phone_group, not both.';
|
|
||||||
$this->auto_http_code(false);
|
|
||||||
|
|
||||||
return $this->json($return);
|
|
||||||
}
|
|
||||||
|
|
||||||
$phone = null;
|
$phone = null;
|
||||||
if ($id_phone)
|
if ($id_phone)
|
||||||
{
|
{
|
||||||
|
@ -537,22 +433,6 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
$phone_group = null;
|
|
||||||
if ($id_phone_group)
|
|
||||||
{
|
|
||||||
$phone_group = $this->internal_phone_group->get_for_user($this->user['id'], $id_phone_group);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($id_phone_group && !$phone_group)
|
|
||||||
{
|
|
||||||
$return = self::DEFAULT_RETURN;
|
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
|
||||||
$return['message'] = self::ERROR_MESSAGES['INVALID_PARAMETER'] . 'id_phone_group : You must specify an id_phone_group number among thoses of user phone groups.';
|
|
||||||
$this->auto_http_code(false);
|
|
||||||
|
|
||||||
return $this->json($return);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mms)
|
if ($mms)
|
||||||
{
|
{
|
||||||
foreach ($files_arrays as $file)
|
foreach ($files_arrays as $file)
|
||||||
|
@ -575,7 +455,7 @@ namespace controllers\publics;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
$scheduled_id = $this->internal_scheduled->create($this->user['id'], $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||||
if (!$scheduled_id)
|
if (!$scheduled_id)
|
||||||
{
|
{
|
||||||
$return = self::DEFAULT_RETURN;
|
$return = self::DEFAULT_RETURN;
|
||||||
|
@ -626,8 +506,6 @@ namespace controllers\publics;
|
||||||
* @param string $_POST['name'] : Phone name
|
* @param string $_POST['name'] : Phone name
|
||||||
* @param string $_POST['adapter'] : Phone adapter
|
* @param string $_POST['adapter'] : Phone adapter
|
||||||
* @param array $_POST['adapter_data'] : Phone adapter data
|
* @param array $_POST['adapter_data'] : Phone adapter data
|
||||||
* @param int $priority : Priority with which to use phone to send SMS. Default 0.
|
|
||||||
* @param ?array $_POST['limits'] : Array of limits in number of SMS for a period to be applied to this phone.
|
|
||||||
*
|
*
|
||||||
* @return int : id phone the new phone on success
|
* @return int : id phone the new phone on success
|
||||||
*/
|
*/
|
||||||
|
@ -638,10 +516,6 @@ namespace controllers\publics;
|
||||||
$name = $_POST['name'] ?? false;
|
$name = $_POST['name'] ?? false;
|
||||||
$adapter = $_POST['adapter'] ?? false;
|
$adapter = $_POST['adapter'] ?? false;
|
||||||
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : [];
|
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : [];
|
||||||
$priority = $_POST['priority'] ?? 0;
|
|
||||||
$priority = max(((int) $priority), 0);
|
|
||||||
$limits = $_POST['limits'] ?? [];
|
|
||||||
$limits = is_array($limits) ? $limits : [$limits];
|
|
||||||
|
|
||||||
if (!$name)
|
if (!$name)
|
||||||
{
|
{
|
||||||
|
@ -661,7 +535,7 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
$name_exist = $this->internal_phone->get_by_name_and_user($this->user['id'], $name);
|
$name_exist = $this->internal_phone->get_by_name($name);
|
||||||
if ($name_exist)
|
if ($name_exist)
|
||||||
{
|
{
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||||
|
@ -671,36 +545,6 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($limits)
|
|
||||||
{
|
|
||||||
foreach ($limits as $key => $limit)
|
|
||||||
{
|
|
||||||
if (!is_array($limit))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$startpoint = $limit['startpoint'] ?? false;
|
|
||||||
$volume = $limit['volume'] ?? false;
|
|
||||||
|
|
||||||
if (!$startpoint || !$volume)
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$volume = (int) $volume;
|
|
||||||
$limits[$key]['volume'] = max($volume, 1);
|
|
||||||
|
|
||||||
if (!\controllers\internals\Tool::validate_relative_date($startpoint))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapters = $this->internal_adapter->list_adapters();
|
$adapters = $this->internal_adapter->list_adapters();
|
||||||
$find_adapter = false;
|
$find_adapter = false;
|
||||||
foreach ($adapters as $metas)
|
foreach ($adapters as $metas)
|
||||||
|
@ -783,7 +627,7 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
$phone_id = $this->internal_phone->create($this->user['id'], $name, $adapter, $adapter_data, $priority, $limits);
|
$phone_id = $this->internal_phone->create($this->user['id'], $name, $adapter, $adapter_data);
|
||||||
if (false === $phone_id)
|
if (false === $phone_id)
|
||||||
{
|
{
|
||||||
$return['error'] = self::ERROR_CODES['CANNOT_CREATE'];
|
$return['error'] = self::ERROR_CODES['CANNOT_CREATE'];
|
||||||
|
@ -806,7 +650,6 @@ namespace controllers\publics;
|
||||||
* @param string (optionnal) $_POST['name'] : New phone name
|
* @param string (optionnal) $_POST['name'] : New phone name
|
||||||
* @param string (optionnal) $_POST['adapter'] : New phone adapter
|
* @param string (optionnal) $_POST['adapter'] : New phone adapter
|
||||||
* @param array (optionnal) $_POST['adapter_data'] : New phone adapter data
|
* @param array (optionnal) $_POST['adapter_data'] : New phone adapter data
|
||||||
* @param int $priority : Priority with which to use phone to send SMS. Default 0.
|
|
||||||
*
|
*
|
||||||
* @return int : id phone the new phone on success
|
* @return int : id phone the new phone on success
|
||||||
*/
|
*/
|
||||||
|
@ -824,16 +667,10 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
$limits = $this->internal_phone->get_limits(($phone['id']));
|
|
||||||
|
|
||||||
$name = $_POST['name'] ?? $phone['name'];
|
$name = $_POST['name'] ?? $phone['name'];
|
||||||
$priority = $_POST['priority'] ?? $phone['priority'];
|
|
||||||
$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'], true);
|
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : json_decode($phone['adapter_data']);
|
||||||
$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 = is_array($limits) ? $limits : [$limits];
|
|
||||||
|
|
||||||
|
|
||||||
if (!$name && !$adapter && !$adapter_data)
|
if (!$name && !$adapter && !$adapter_data)
|
||||||
|
@ -846,7 +683,7 @@ namespace controllers\publics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$phone_with_same_name = $this->internal_phone->get_by_name_and_user($this->user['id'], $name);
|
$phone_with_same_name = $this->internal_phone->get_by_name($name);
|
||||||
if ($phone_with_same_name && $phone_with_same_name['id'] != $phone['id'])
|
if ($phone_with_same_name && $phone_with_same_name['id'] != $phone['id'])
|
||||||
{
|
{
|
||||||
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
$return['error'] = self::ERROR_CODES['INVALID_PARAMETER'];
|
||||||
|
@ -856,36 +693,6 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($limits)
|
|
||||||
{
|
|
||||||
foreach ($limits as $key => $limit)
|
|
||||||
{
|
|
||||||
if (!is_array($limit))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$startpoint = $limit['startpoint'] ?? false;
|
|
||||||
$volume = $limit['volume'] ?? false;
|
|
||||||
|
|
||||||
if (!$startpoint || !$volume)
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$volume = (int) $volume;
|
|
||||||
$limits[$key]['volume'] = max($volume, 1);
|
|
||||||
|
|
||||||
if (!\controllers\internals\Tool::validate_relative_date($startpoint))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapters = $this->internal_adapter->list_adapters();
|
$adapters = $this->internal_adapter->list_adapters();
|
||||||
$find_adapter = false;
|
$find_adapter = false;
|
||||||
foreach ($adapters as $metas)
|
foreach ($adapters as $metas)
|
||||||
|
@ -968,7 +775,7 @@ namespace controllers\publics;
|
||||||
return $this->json($return);
|
return $this->json($return);
|
||||||
}
|
}
|
||||||
|
|
||||||
$success = $this->internal_phone->update_for_user($this->user['id'], $phone['id'], $name, $adapter, $adapter_data_json, $priority, $limits);
|
$success = $this->internal_phone->update_for_user($this->user['id'], $phone['id'], $name, $adapter, $adapter_data);
|
||||||
if (!$success)
|
if (!$success)
|
||||||
{
|
{
|
||||||
$return['error'] = self::ERROR_CODES['CANNOT_UPDATE'];
|
$return['error'] = self::ERROR_CODES['CANNOT_UPDATE'];
|
||||||
|
@ -1010,62 +817,4 @@ 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If user have activated phone limits, check if RaspiSMS phone limit have already been reached
|
|
||||||
$limit_reached = false;
|
|
||||||
if ((int) ($this->user['settings']['phone_limit'] ?? false))
|
|
||||||
{
|
|
||||||
$limits = $this->internal_phone->get_limits($id);
|
|
||||||
|
|
||||||
$remaining_volume = PHP_INT_MAX;
|
|
||||||
foreach ($limits as $limit)
|
|
||||||
{
|
|
||||||
$startpoint = new \DateTime($limit['startpoint']);
|
|
||||||
$consumed = $this->internal_sended->count_since_for_phone_and_user($this->user['id'], $id, $startpoint);
|
|
||||||
$remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($remaining_volume < 1)
|
|
||||||
{
|
|
||||||
$limit_reached = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($limit_reached)
|
|
||||||
{
|
|
||||||
$new_status = \models\Phone::STATUS_LIMIT_REACHED;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Check status on provider side
|
|
||||||
$adapter_classname = $phone['adapter'];
|
|
||||||
$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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,45 +185,6 @@ namespace controllers\publics;
|
||||||
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
|
return $this->redirect(\descartes\Router::url('ConditionalGroup', 'list'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return contacts of a group as json array
|
|
||||||
* @param int $id_group = Group id
|
|
||||||
*
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public function preview (int $id_group)
|
|
||||||
{
|
|
||||||
$return = [
|
|
||||||
'success' => false,
|
|
||||||
'result' => 'Une erreur inconnue est survenue.',
|
|
||||||
];
|
|
||||||
|
|
||||||
$group = $this->internal_conditional_group->get_for_user($_SESSION['user']['id'], $id_group);
|
|
||||||
|
|
||||||
if (!$group)
|
|
||||||
{
|
|
||||||
$return['result'] = 'Ce groupe n\'existe pas.';
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$contacts = $this->internal_conditional_group->get_contacts_for_condition_and_user($_SESSION['user']['id'], $group['condition']);
|
|
||||||
if (!$contacts)
|
|
||||||
{
|
|
||||||
$return['result'] = 'Aucun contact dans le groupe.';
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$return['success'] = true;
|
|
||||||
$return['result'] = array_values($contacts);
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to get the preview of contacts for a conditionnal group.
|
* Try to get the preview of contacts for a conditionnal group.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
namespace controllers\publics;
|
namespace controllers\publics;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page des contacts.
|
* Page des contacts.
|
||||||
*/
|
*/
|
||||||
|
@ -347,28 +345,39 @@ use Exception;
|
||||||
return $this->redirect(\descartes\Router::url('Contact', 'list'));
|
return $this->redirect(\descartes\Router::url('Contact', 'list'));
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
//Try to import file
|
||||||
|
$invalid_type = false;
|
||||||
|
|
||||||
|
switch ($read_file['mime_type'])
|
||||||
{
|
{
|
||||||
$result = false;
|
case 'text/csv':
|
||||||
switch (true)
|
|
||||||
{
|
|
||||||
case ($read_file['mime_type'] === 'text/csv' || 'csv' === $read_file['extension']) :
|
|
||||||
$result = $this->internal_contact->import_csv($id_user, $read_file['content']);
|
$result = $this->internal_contact->import_csv($id_user, $read_file['content']);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ($read_file['mime_type'] === 'text/json' || 'json' === $read_file['extension']) :
|
case 'application/json':
|
||||||
$result = $this->internal_contact->import_json($id_user, $read_file['content']);
|
$result = $this->internal_contact->import_json($id_user, $read_file['content']);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Exception('Le type de fichier n\'est pas valide.');
|
if ('csv' === $read_file['extension'])
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (\Exception $e)
|
|
||||||
{
|
{
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Erreur lors de l\'import: ' . $e->getMessage());
|
$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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($invalid_type)
|
||||||
|
{
|
||||||
|
\FlashMessage\FlashMessage::push('danger', 'Le type de fichier n\'est pas valide.');
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('Contact', 'list'));
|
return $this->redirect(\descartes\Router::url('Contact', 'list'));
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,12 +87,11 @@ namespace controllers\publics;
|
||||||
$stats_start_date_formated = $stats_start_date->format('Y-m-d');
|
$stats_start_date_formated = $stats_start_date->format('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
$nb_sendeds_by_day = $this->internal_sended->count_by_day_and_status_since_for_user($id_user, $stats_start_date_formated);
|
$nb_sendeds_by_day = $this->internal_sended->count_by_day_since_for_user($id_user, $stats_start_date_formated);
|
||||||
$nb_receiveds_by_day = $this->internal_received->count_by_day_since_for_user($id_user, $stats_start_date_formated);
|
$nb_receiveds_by_day = $this->internal_received->count_by_day_since_for_user($id_user, $stats_start_date_formated);
|
||||||
|
|
||||||
//On va traduire ces données pour les afficher en graphique
|
//On va traduire ces données pour les afficher en graphique
|
||||||
$array_bar_chart_sended = [];
|
$array_area_chart = [];
|
||||||
$array_bar_chart_received = [];
|
|
||||||
|
|
||||||
$date = clone $stats_start_date;
|
$date = clone $stats_start_date;
|
||||||
$one_day = new \DateInterval('P1D');
|
$one_day = new \DateInterval('P1D');
|
||||||
|
@ -102,15 +101,12 @@ namespace controllers\publics;
|
||||||
while ($date <= $now)
|
while ($date <= $now)
|
||||||
{
|
{
|
||||||
$date_f = $date->format('Y-m-d');
|
$date_f = $date->format('Y-m-d');
|
||||||
$array_bar_chart_sended[$date_f] = [
|
$array_area_chart[$date_f] = [
|
||||||
'period' => $date_f,
|
'period' => $date_f,
|
||||||
'sendeds_failed' => 0,
|
'sendeds' => 0,
|
||||||
'sendeds_unknown' => 0,
|
'receiveds' => 0,
|
||||||
'sendeds_delivered' => 0,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$array_bar_chart_received[$date_f] = ['period' => $date_f, 'receiveds' => 0];
|
|
||||||
|
|
||||||
$date->add($one_day);
|
$date->add($one_day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,16 +114,15 @@ namespace controllers\publics;
|
||||||
$total_receiveds = 0;
|
$total_receiveds = 0;
|
||||||
|
|
||||||
//0n remplie le tableau avec les données adaptées
|
//0n remplie le tableau avec les données adaptées
|
||||||
foreach ($nb_sendeds_by_day as $nb_sended)
|
foreach ($nb_sendeds_by_day as $date => $nb_sended)
|
||||||
{
|
{
|
||||||
$array_bar_chart_sended[$nb_sended['at_ymd']]['sendeds_' . $nb_sended['status']] = $nb_sended['nb'];
|
$array_area_chart[$date]['sendeds'] = $nb_sended;
|
||||||
$array_bar_chart_sended[$nb_sended['at_ymd']]['sendeds_total'] = ($array_bar_chart_sended[$nb_sended['at_ymd']]['sendeds_total'] ?? 0) + $nb_sended['nb'];
|
$total_sendeds += $nb_sended;
|
||||||
$total_sendeds += $nb_sended['nb'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($nb_receiveds_by_day as $date => $nb_received)
|
foreach ($nb_receiveds_by_day as $date => $nb_received)
|
||||||
{
|
{
|
||||||
$array_bar_chart_received[$date]['receiveds'] = $nb_received;
|
$array_area_chart[$date]['receiveds'] = $nb_received;
|
||||||
$total_receiveds += $nb_received;
|
$total_receiveds += $nb_received;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,8 +130,7 @@ namespace controllers\publics;
|
||||||
$avg_sendeds = round($total_sendeds / $nb_days, 2);
|
$avg_sendeds = round($total_sendeds / $nb_days, 2);
|
||||||
$avg_receiveds = round($total_receiveds / $nb_days, 2);
|
$avg_receiveds = round($total_receiveds / $nb_days, 2);
|
||||||
|
|
||||||
$array_bar_chart_sended = array_values($array_bar_chart_sended);
|
$array_area_chart = array_values($array_area_chart);
|
||||||
$array_bar_chart_received = array_values($array_bar_chart_received);
|
|
||||||
|
|
||||||
$this->render('dashboard/show', [
|
$this->render('dashboard/show', [
|
||||||
'nb_contacts' => $nb_contacts,
|
'nb_contacts' => $nb_contacts,
|
||||||
|
@ -151,9 +145,7 @@ namespace controllers\publics;
|
||||||
'sendeds' => $sendeds,
|
'sendeds' => $sendeds,
|
||||||
'receiveds' => $receiveds,
|
'receiveds' => $receiveds,
|
||||||
'events' => $events,
|
'events' => $events,
|
||||||
'data_bar_chart_sended' => json_encode($array_bar_chart_sended),
|
'data_area_chart' => json_encode($array_area_chart),
|
||||||
'data_bar_chart_received' => json_encode($array_bar_chart_received),
|
|
||||||
'stats_start_date_formated' => $stats_start_date_formated,
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -234,7 +234,6 @@ namespace controllers\publics;
|
||||||
$at = $now;
|
$at = $now;
|
||||||
$text = $_POST['text'] ?? '';
|
$text = $_POST['text'] ?? '';
|
||||||
$destination = $_POST['destination'] ?? false;
|
$destination = $_POST['destination'] ?? false;
|
||||||
$tag = $_POST['tag'] ?? null;
|
|
||||||
$id_phone = $_POST['id_phone'] ?? false;
|
$id_phone = $_POST['id_phone'] ?? false;
|
||||||
$files = $_FILES['medias'] ?? false;
|
$files = $_FILES['medias'] ?? false;
|
||||||
|
|
||||||
|
@ -316,7 +315,7 @@ namespace controllers\publics;
|
||||||
//Destinations must be an array of number
|
//Destinations must be an array of number
|
||||||
$destinations = [['number' => $destination, 'data' => '[]']];
|
$destinations = [['number' => $destination, 'data' => '[]']];
|
||||||
|
|
||||||
if (!$this->internal_scheduled->create($id_user, $at, $text, $id_phone, null, false, $mms, $tag, $destinations, [], [], [], $media_ids))
|
if (!$this->internal_scheduled->create($id_user, $at, $text, $id_phone, false, $mms, $destinations, [], [], [], $media_ids))
|
||||||
{
|
{
|
||||||
$return['success'] = false;
|
$return['success'] = false;
|
||||||
$return['message'] = 'Impossible de créer le Sms';
|
$return['message'] = 'Impossible de créer le Sms';
|
||||||
|
|
|
@ -191,45 +191,6 @@ namespace controllers\publics;
|
||||||
return $this->redirect(\descartes\Router::url('Group', 'list'));
|
return $this->redirect(\descartes\Router::url('Group', 'list'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return contacts of a group as json array
|
|
||||||
* @param int $id_group = Group id
|
|
||||||
*
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public function preview (int $id_group)
|
|
||||||
{
|
|
||||||
$return = [
|
|
||||||
'success' => false,
|
|
||||||
'result' => 'Une erreur inconnue est survenue.',
|
|
||||||
];
|
|
||||||
|
|
||||||
$group = $this->internal_group->get_for_user($_SESSION['user']['id'], $id_group);
|
|
||||||
|
|
||||||
if (!$group)
|
|
||||||
{
|
|
||||||
$return['result'] = 'Ce groupe n\'existe pas.';
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$contacts = $this->internal_group->get_contacts($id_group);
|
|
||||||
if (!$contacts)
|
|
||||||
{
|
|
||||||
$return['result'] = 'Aucun contact dans le groupe.';
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$return['success'] = true;
|
|
||||||
$return['result'] = $contacts;
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cette fonction retourne la liste des groups sous forme JSON.
|
* Cette fonction retourne la liste des groups sous forme JSON.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -18,13 +18,11 @@ class Phone extends \descartes\Controller
|
||||||
{
|
{
|
||||||
private $internal_phone;
|
private $internal_phone;
|
||||||
private $internal_adapter;
|
private $internal_adapter;
|
||||||
private $internal_sended;
|
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
||||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
||||||
$this->internal_sended = new \controllers\internals\Sended($bdd);
|
|
||||||
$this->internal_adapter = new \controllers\internals\Adapter();
|
$this->internal_adapter = new \controllers\internals\Adapter();
|
||||||
|
|
||||||
\controllers\internals\Tool::verifyconnect();
|
\controllers\internals\Tool::verifyconnect();
|
||||||
|
@ -57,9 +55,6 @@ class Phone extends \descartes\Controller
|
||||||
|
|
||||||
foreach ($phones as &$phone)
|
foreach ($phones as &$phone)
|
||||||
{
|
{
|
||||||
$limits = $this->internal_phone->get_limits($phone['id']);
|
|
||||||
$phone['limits'] = $limits;
|
|
||||||
|
|
||||||
$adapter = $adapters[$phone['adapter']] ?? false;
|
$adapter = $adapters[$phone['adapter']] ?? false;
|
||||||
|
|
||||||
if (!$adapter)
|
if (!$adapter)
|
||||||
|
@ -90,11 +85,6 @@ 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');
|
||||||
|
@ -143,9 +133,7 @@ class Phone extends \descartes\Controller
|
||||||
* @param $csrf : CSRF token
|
* @param $csrf : CSRF token
|
||||||
* @param string $_POST['name'] : Phone name
|
* @param string $_POST['name'] : Phone name
|
||||||
* @param string $_POST['adapter'] : Phone adapter
|
* @param string $_POST['adapter'] : Phone adapter
|
||||||
* @param ?array $_POST['adapter_data'] : Phone adapter data
|
* @param array $_POST['adapter_data'] : Phone adapter data
|
||||||
* @param ?array $_POST['limits'] : Array of limits in number of SMS for a period to be applied to this phone.
|
|
||||||
* @param int $_POST['priority'] : Priority with which to use phone to send SMS. Default 0.
|
|
||||||
*/
|
*/
|
||||||
public function create($csrf)
|
public function create($csrf)
|
||||||
{
|
{
|
||||||
|
@ -158,12 +146,8 @@ class Phone extends \descartes\Controller
|
||||||
|
|
||||||
$id_user = $_SESSION['user']['id'];
|
$id_user = $_SESSION['user']['id'];
|
||||||
$name = $_POST['name'] ?? false;
|
$name = $_POST['name'] ?? false;
|
||||||
$priority = $_POST['priority'] ?? 0;
|
|
||||||
$priority = max(((int) $priority), 0);
|
|
||||||
$adapter = $_POST['adapter'] ?? false;
|
$adapter = $_POST['adapter'] ?? false;
|
||||||
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : [];
|
$adapter_data = !empty($_POST['adapter_data']) ? $_POST['adapter_data'] : [];
|
||||||
$limits = $_POST['limits'] ?? [];
|
|
||||||
$limits = is_array($limits) ? $limits : [$limits];
|
|
||||||
|
|
||||||
if (!$name || !$adapter)
|
if (!$name || !$adapter)
|
||||||
{
|
{
|
||||||
|
@ -172,7 +156,7 @@ class Phone extends \descartes\Controller
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$name_exist = $this->internal_phone->get_by_name_and_user($id_user, $name);
|
$name_exist = $this->internal_phone->get_by_name($name);
|
||||||
if ($name_exist)
|
if ($name_exist)
|
||||||
{
|
{
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Ce nom est déjà utilisé pour un autre téléphone.');
|
\FlashMessage\FlashMessage::push('danger', 'Ce nom est déjà utilisé pour un autre téléphone.');
|
||||||
|
@ -180,36 +164,6 @@ class Phone extends \descartes\Controller
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($limits)
|
|
||||||
{
|
|
||||||
foreach ($limits as $key => $limit)
|
|
||||||
{
|
|
||||||
if (!is_array($limit))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$startpoint = $limit['startpoint'] ?? false;
|
|
||||||
$volume = $limit['volume'] ?? false;
|
|
||||||
|
|
||||||
if (!$startpoint || !$volume)
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$volume = (int) $volume;
|
|
||||||
$limits[$key]['volume'] = max($volume, 1);
|
|
||||||
|
|
||||||
if (!\controllers\internals\Tool::validate_relative_date($startpoint))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapters = $this->internal_adapter->list_adapters();
|
$adapters = $this->internal_adapter->list_adapters();
|
||||||
$find_adapter = false;
|
$find_adapter = false;
|
||||||
foreach ($adapters as $metas)
|
foreach ($adapters as $metas)
|
||||||
|
@ -291,7 +245,7 @@ class Phone extends \descartes\Controller
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$success = $this->internal_phone->create($id_user, $name, $adapter, $adapter_data, $priority, $limits);
|
$success = $this->internal_phone->create($id_user, $name, $adapter, $adapter_data);
|
||||||
if (!$success)
|
if (!$success)
|
||||||
{
|
{
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce téléphone.');
|
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce téléphone.');
|
||||||
|
@ -303,290 +257,4 @@ class Phone extends \descartes\Controller
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the edit page for phones
|
|
||||||
*
|
|
||||||
* @param int... $ids : Phones ids
|
|
||||||
*/
|
|
||||||
public function edit()
|
|
||||||
{
|
|
||||||
$ids = $_GET['ids'] ?? [];
|
|
||||||
$id_user = $_SESSION['user']['id'];
|
|
||||||
|
|
||||||
$phones = $this->internal_phone->gets_in_for_user($id_user, $ids);
|
|
||||||
|
|
||||||
if (!$phones)
|
|
||||||
{
|
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapters = $this->internal_adapter->list_adapters();
|
|
||||||
|
|
||||||
foreach ($phones as &$phone)
|
|
||||||
{
|
|
||||||
$limits = $this->internal_phone->get_limits($phone['id']);
|
|
||||||
$phone['limits'] = $limits;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->render('phone/edit', [
|
|
||||||
'phones' => $phones,
|
|
||||||
'adapters' => $adapters,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update multiple phones.
|
|
||||||
*
|
|
||||||
* @param $csrf : CSRF token
|
|
||||||
* @param string $_POST['phones']['id']['name'] : Phone name
|
|
||||||
* @param string $_POST['phones']['id']['adapter'] : Phone adapter
|
|
||||||
* @param ?array $_POST['phones']['id']['adapter_data'] : Phone adapter data
|
|
||||||
* @param ?array $_POST['phones']['id']['limits'] : Array of limits in number of SMS for a period to be applied to this phone.
|
|
||||||
* @param int $_POST['phones']['id']['priority'] : Priority with which to use phone to send SMS. Default 0.
|
|
||||||
*/
|
|
||||||
public function update($csrf)
|
|
||||||
{
|
|
||||||
if (!$this->verify_csrf($csrf))
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'add'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$_POST['phones'])
|
|
||||||
{
|
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$id_user = $_SESSION['user']['id'];
|
|
||||||
|
|
||||||
$nb_update = 0;
|
|
||||||
foreach ($_POST['phones'] as $id_phone => $phone)
|
|
||||||
{
|
|
||||||
$name = $phone['name'] ?? false;
|
|
||||||
$priority = $phone['priority'] ?? 0;
|
|
||||||
$priority = max(((int) $priority), 0);
|
|
||||||
$adapter = $phone['adapter'] ?? false;
|
|
||||||
$adapter_data = !empty($phone['adapter_data']) ? $phone['adapter_data'] : [];
|
|
||||||
$limits = $phone['limits'] ?? [];
|
|
||||||
$limits = is_array($limits) ? $limits : [$limits];
|
|
||||||
|
|
||||||
if (!$name || !$adapter)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$phone_with_same_name = $this->internal_phone->get_by_name_and_user($id_user, $name);
|
|
||||||
if ($phone_with_same_name && $phone_with_same_name['id'] != $id_phone)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($limits)
|
|
||||||
{
|
|
||||||
foreach ($limits as $key => $limit)
|
|
||||||
{
|
|
||||||
if (!is_array($limit))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$startpoint = $limit['startpoint'] ?? false;
|
|
||||||
$volume = $limit['volume'] ?? false;
|
|
||||||
|
|
||||||
if (!$startpoint || !$volume)
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$volume = (int) $volume;
|
|
||||||
$limits[$key]['volume'] = max($volume, 1);
|
|
||||||
|
|
||||||
if (!\controllers\internals\Tool::validate_relative_date($startpoint))
|
|
||||||
{
|
|
||||||
unset($limits[$key]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapters = $this->internal_adapter->list_adapters();
|
|
||||||
$find_adapter = false;
|
|
||||||
foreach ($adapters as $metas)
|
|
||||||
{
|
|
||||||
if ($metas['meta_classname'] === $adapter)
|
|
||||||
{
|
|
||||||
$find_adapter = $metas;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$find_adapter)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If missing required data fields, error
|
|
||||||
foreach ($find_adapter['meta_data_fields'] as $field)
|
|
||||||
{
|
|
||||||
if (false === $field['required'])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($adapter_data[$field['name']]))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If field phone number is invalid
|
|
||||||
foreach ($find_adapter['meta_data_fields'] as $field)
|
|
||||||
{
|
|
||||||
if ('phone_number' !== ($field['type'] ?? false))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($adapter_data[$field['name']]))
|
|
||||||
{
|
|
||||||
$adapter_data[$field['name']] = \controllers\internals\Tool::parse_phone($adapter_data[$field['name']]);
|
|
||||||
|
|
||||||
if ($adapter_data[$field['name']])
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
$adapter_data = json_encode($adapter_data);
|
|
||||||
|
|
||||||
//Check adapter is working correctly with thoses names and data
|
|
||||||
$adapter_classname = $find_adapter['meta_classname'];
|
|
||||||
$adapter_instance = new $adapter_classname($adapter_data);
|
|
||||||
$adapter_working = $adapter_instance->test();
|
|
||||||
|
|
||||||
if (!$adapter_working)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$success = $this->internal_phone->update_for_user($id_user, $id_phone, $name, $adapter, $adapter_data, $priority, $limits);
|
|
||||||
if (!$success)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$nb_update ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($nb_update !== \count($_POST['phones']))
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Certains téléphones n\'ont pas pu êtres mis à jour.');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('Phone', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
\FlashMessage\FlashMessage::push('success', 'Tous les téléphones ont été modifiés avec succès.');
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// If user have activated phone limits, check if RaspiSMS phone limit have already been reached
|
|
||||||
$limit_reached = false;
|
|
||||||
if ((int) ($_SESSION['user']['settings']['phone_limit'] ?? false))
|
|
||||||
{
|
|
||||||
$limits = $this->internal_phone->get_limits($id);
|
|
||||||
|
|
||||||
$remaining_volume = PHP_INT_MAX;
|
|
||||||
foreach ($limits as $limit)
|
|
||||||
{
|
|
||||||
$startpoint = new \DateTime($limit['startpoint']);
|
|
||||||
$consumed = $this->internal_sended->count_since_for_phone_and_user($_SESSION['user']['id'], $id, $startpoint);
|
|
||||||
$remaining_volume = min(($limit['volume'] - $consumed), $remaining_volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($remaining_volume < 1)
|
|
||||||
{
|
|
||||||
$limit_reached = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($limit_reached)
|
|
||||||
{
|
|
||||||
$new_status = \models\Phone::STATUS_LIMIT_REACHED;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Check status on provider side
|
|
||||||
$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'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of phones as a JSON array
|
|
||||||
*/
|
|
||||||
public function json_list()
|
|
||||||
{
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
echo json_encode($this->internal_phone->list_for_user($_SESSION['user']['id']));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
<?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\publics;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Page of phone groups.
|
|
||||||
*/
|
|
||||||
class PhoneGroup extends \descartes\Controller
|
|
||||||
{
|
|
||||||
private $internal_phone_group;
|
|
||||||
private $internal_phone;
|
|
||||||
private $internal_event;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call before any other func to check user is connected
|
|
||||||
*
|
|
||||||
* @return void;
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
|
||||||
|
|
||||||
$this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd);
|
|
||||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
|
||||||
$this->internal_event = new \controllers\internals\Event($bdd);
|
|
||||||
|
|
||||||
\controllers\internals\Tool::verifyconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all groups as an array for administration.
|
|
||||||
*/
|
|
||||||
public function list()
|
|
||||||
{
|
|
||||||
$this->render('phone_group/list');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return groups as json.
|
|
||||||
*/
|
|
||||||
public function list_json()
|
|
||||||
{
|
|
||||||
$entities = $this->internal_phone_group->list_for_user($_SESSION['user']['id']);
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
echo json_encode(['data' => $entities]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a list of phone groups
|
|
||||||
*
|
|
||||||
* @param array int $_GET['ids'] : Ids of phone groups to delete
|
|
||||||
* @param mixed $csrf
|
|
||||||
*
|
|
||||||
* @return boolean;
|
|
||||||
*/
|
|
||||||
public function delete($csrf)
|
|
||||||
{
|
|
||||||
if (!$this->verify_csrf($csrf))
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$ids = $_GET['ids'] ?? [];
|
|
||||||
foreach ($ids as $id)
|
|
||||||
{
|
|
||||||
$this->internal_phone_group->delete_for_user($_SESSION['user']['id'], $id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the creation page of a group
|
|
||||||
*/
|
|
||||||
public function add()
|
|
||||||
{
|
|
||||||
$this->render('phone_group/add');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the edition page for phone groups
|
|
||||||
*
|
|
||||||
* @param array $_GET['ids'] : Ids of phone groups to edit
|
|
||||||
*/
|
|
||||||
public function edit()
|
|
||||||
{
|
|
||||||
$ids = $_GET['ids'] ?? [];
|
|
||||||
|
|
||||||
$groups = $this->internal_phone_group->gets_in_for_user($_SESSION['user']['id'], $ids);
|
|
||||||
|
|
||||||
foreach ($groups as $key => $group)
|
|
||||||
{
|
|
||||||
$groups[$key]['phones'] = $this->internal_phone_group->get_phones($group['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->render('phone_group/edit', [
|
|
||||||
'phone_groups' => $groups,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new phone group
|
|
||||||
*
|
|
||||||
* @param $csrf : CSRF token
|
|
||||||
* @param string $_POST['name'] : Name of phone group
|
|
||||||
* @param array $_POST['phones'] : Ids of phones to put in the group
|
|
||||||
*/
|
|
||||||
public function create($csrf)
|
|
||||||
{
|
|
||||||
if (!$this->verify_csrf($csrf))
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'add'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$name = $_POST['name'] ?? false;
|
|
||||||
$phones_ids = $_POST['phones'] ?? false;
|
|
||||||
|
|
||||||
if (!$name || !$phones_ids)
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Des champs sont manquants !');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'add'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$id_group = $this->internal_phone_group->create($_SESSION['user']['id'], $name, $phones_ids);
|
|
||||||
if (!$id_group)
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer ce groupe.');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'add'));
|
|
||||||
}
|
|
||||||
|
|
||||||
\FlashMessage\FlashMessage::push('success', 'Le groupe a bien été créé.');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update a list of phone groups
|
|
||||||
*
|
|
||||||
* @param $csrf : CSRF token
|
|
||||||
* @param array $_POST['phone_groups'] : An array of phone groups with group id as keys
|
|
||||||
*
|
|
||||||
* @return boolean;
|
|
||||||
*/
|
|
||||||
public function update($csrf)
|
|
||||||
{
|
|
||||||
if (!$this->verify_csrf($csrf))
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Jeton CSRF invalid !');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$groups = $_POST['phone_groups'] ?? [];
|
|
||||||
|
|
||||||
$nb_groups_update = 0;
|
|
||||||
foreach ($groups as $id => $group)
|
|
||||||
{
|
|
||||||
foreach ($group['phones_ids'] as $key => $value)
|
|
||||||
{
|
|
||||||
$group['phones_ids'][$key] = (int) $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$nb_groups_update += (int) $this->internal_phone_group->update_for_user($_SESSION['user']['id'], $id, $group['name'], $group['phones_ids']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($nb_groups_update !== \count($groups))
|
|
||||||
{
|
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Certains groupes n\'ont pas pu êtres mis à jour.');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
\FlashMessage\FlashMessage::push('success', 'Tous les groupes ont été modifiés avec succès.');
|
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('PhoneGroup', 'list'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return phones of a group as json array
|
|
||||||
* @param int $id_group = PhoneGroup id
|
|
||||||
*
|
|
||||||
* @return json
|
|
||||||
*/
|
|
||||||
public function preview (int $id_group)
|
|
||||||
{
|
|
||||||
$return = [
|
|
||||||
'success' => false,
|
|
||||||
'result' => 'Une erreur inconnue est survenue.',
|
|
||||||
];
|
|
||||||
|
|
||||||
$group = $this->internal_phone_group->get_for_user($_SESSION['user']['id'], $id_group);
|
|
||||||
|
|
||||||
if (!$group)
|
|
||||||
{
|
|
||||||
$return['result'] = 'Ce groupe n\'existe pas.';
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$phones = $this->internal_phone_group->get_phones($id_group);
|
|
||||||
if (!$phones)
|
|
||||||
{
|
|
||||||
$return['result'] = 'Aucun téléphone dans le groupe.';
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($phones as &$phone)
|
|
||||||
{
|
|
||||||
$phone['adapter_name'] = call_user_func([$phone['adapter'], 'meta_name']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$return['success'] = true;
|
|
||||||
$return['result'] = $phones;
|
|
||||||
echo json_encode($return);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cette fonction retourne la liste des groups sous forme JSON.
|
|
||||||
*/
|
|
||||||
public function json_list()
|
|
||||||
{
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
echo json_encode($this->internal_phone_group->list_for_user($_SESSION['user']['id']));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,7 +18,6 @@ namespace controllers\publics;
|
||||||
{
|
{
|
||||||
private $internal_scheduled;
|
private $internal_scheduled;
|
||||||
private $internal_phone;
|
private $internal_phone;
|
||||||
private $internal_phone_group;
|
|
||||||
private $internal_contact;
|
private $internal_contact;
|
||||||
private $internal_group;
|
private $internal_group;
|
||||||
private $internal_conditional_group;
|
private $internal_conditional_group;
|
||||||
|
@ -35,7 +34,6 @@ namespace controllers\publics;
|
||||||
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
$bdd = \descartes\Model::_connect(DATABASE_HOST, DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
|
||||||
$this->internal_scheduled = new \controllers\internals\Scheduled($bdd);
|
$this->internal_scheduled = new \controllers\internals\Scheduled($bdd);
|
||||||
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
$this->internal_phone = new \controllers\internals\Phone($bdd);
|
||||||
$this->internal_phone_group = new \controllers\internals\PhoneGroup($bdd);
|
|
||||||
$this->internal_contact = new \controllers\internals\Contact($bdd);
|
$this->internal_contact = new \controllers\internals\Contact($bdd);
|
||||||
$this->internal_group = new \controllers\internals\Group($bdd);
|
$this->internal_group = new \controllers\internals\Group($bdd);
|
||||||
$this->internal_conditional_group = new \controllers\internals\ConditionalGroup($bdd);
|
$this->internal_conditional_group = new \controllers\internals\ConditionalGroup($bdd);
|
||||||
|
@ -120,7 +118,6 @@ namespace controllers\publics;
|
||||||
|
|
||||||
$contacts = $this->internal_contact->gets_for_user($id_user);
|
$contacts = $this->internal_contact->gets_for_user($id_user);
|
||||||
$phones = $this->internal_phone->gets_for_user($id_user);
|
$phones = $this->internal_phone->gets_for_user($id_user);
|
||||||
$phone_groups = $this->internal_phone_group->gets_for_user($id_user);
|
|
||||||
|
|
||||||
$contact_ids = (isset($_GET['contact_ids']) && \is_array($_GET['contact_ids'])) ? $_GET['contact_ids'] : [];
|
$contact_ids = (isset($_GET['contact_ids']) && \is_array($_GET['contact_ids'])) ? $_GET['contact_ids'] : [];
|
||||||
$group_ids = (isset($_GET['group_ids']) && \is_array($_GET['group_ids'])) ? $_GET['group_ids'] : [];
|
$group_ids = (isset($_GET['group_ids']) && \is_array($_GET['group_ids'])) ? $_GET['group_ids'] : [];
|
||||||
|
@ -156,7 +153,6 @@ namespace controllers\publics;
|
||||||
'now' => $now->format('Y-m-d H:i'),
|
'now' => $now->format('Y-m-d H:i'),
|
||||||
'contacts' => $contacts,
|
'contacts' => $contacts,
|
||||||
'phones' => $phones,
|
'phones' => $phones,
|
||||||
'phone_groups' => $phone_groups,
|
|
||||||
'prefilled_contacts' => $prefilled_contacts,
|
'prefilled_contacts' => $prefilled_contacts,
|
||||||
'prefilled_groups' => $prefilled_groups,
|
'prefilled_groups' => $prefilled_groups,
|
||||||
'prefilled_conditional_groups' => $prefilled_conditional_groups,
|
'prefilled_conditional_groups' => $prefilled_conditional_groups,
|
||||||
|
@ -183,7 +179,6 @@ namespace controllers\publics;
|
||||||
|
|
||||||
$all_contacts = $this->internal_contact->gets_for_user($_SESSION['user']['id']);
|
$all_contacts = $this->internal_contact->gets_for_user($_SESSION['user']['id']);
|
||||||
$phones = $this->internal_phone->gets_for_user($_SESSION['user']['id']);
|
$phones = $this->internal_phone->gets_for_user($_SESSION['user']['id']);
|
||||||
$phone_groups = $this->internal_phone_group->gets_for_user($id_user);
|
|
||||||
$scheduleds = $this->internal_scheduled->gets_in_for_user($_SESSION['user']['id'], $ids);
|
$scheduleds = $this->internal_scheduled->gets_in_for_user($_SESSION['user']['id'], $ids);
|
||||||
|
|
||||||
//Pour chaque message on ajoute les numéros, les contacts & les groups
|
//Pour chaque message on ajoute les numéros, les contacts & les groups
|
||||||
|
@ -231,7 +226,6 @@ namespace controllers\publics;
|
||||||
$this->render('scheduled/edit', [
|
$this->render('scheduled/edit', [
|
||||||
'scheduleds' => $scheduleds,
|
'scheduleds' => $scheduleds,
|
||||||
'phones' => $phones,
|
'phones' => $phones,
|
||||||
'phone_groups' => $phone_groups,
|
|
||||||
'contacts' => $all_contacts,
|
'contacts' => $all_contacts,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +238,7 @@ namespace controllers\publics;
|
||||||
* @param string $_POST['at'] : Date to send message for
|
* @param string $_POST['at'] : Date to send message for
|
||||||
* @param string $_POST['text'] : Text of the message
|
* @param string $_POST['text'] : Text of the message
|
||||||
* @param ?bool $_POST['flash'] : Is the message a flash message (by default false)
|
* @param ?bool $_POST['flash'] : Is the message a flash message (by default false)
|
||||||
* @param ?int $_POST['id_phone'] : Id of the phone or phone group to send message from. id will be preceed by phone_ of phonegroup_ depending on type of ressource to use, if null use random phone
|
* @param ?int $_POST['id_phone'] : Id of the phone to send message from, if null use random phone
|
||||||
* @param ?array $_POST['numbers'] : Numbers to send the message to
|
* @param ?array $_POST['numbers'] : Numbers to send the message to
|
||||||
* @param ?array $_POST['contacts'] : Numbers to send the message to
|
* @param ?array $_POST['contacts'] : Numbers to send the message to
|
||||||
* @param ?array $_POST['groups'] : Numbers to send the message to
|
* @param ?array $_POST['groups'] : Numbers to send the message to
|
||||||
|
@ -264,7 +258,6 @@ namespace controllers\publics;
|
||||||
$at = $_POST['at'] ?? false;
|
$at = $_POST['at'] ?? false;
|
||||||
$text = $_POST['text'] ?? false;
|
$text = $_POST['text'] ?? false;
|
||||||
$flash = (bool) ($_POST['flash'] ?? false);
|
$flash = (bool) ($_POST['flash'] ?? false);
|
||||||
$tag = ($_POST['tag'] ?? null) ?: null;
|
|
||||||
$id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone'];
|
$id_phone = empty($_POST['id_phone']) ? null : $_POST['id_phone'];
|
||||||
$numbers = $_POST['numbers'] ?? [];
|
$numbers = $_POST['numbers'] ?? [];
|
||||||
$numbers = is_array($numbers) ? $numbers : [$numbers];
|
$numbers = is_array($numbers) ? $numbers : [$numbers];
|
||||||
|
@ -440,15 +433,7 @@ namespace controllers\publics;
|
||||||
|
|
||||||
$mms = (bool) count($media_ids);
|
$mms = (bool) count($media_ids);
|
||||||
|
|
||||||
// Check if we must send message to a phone or a phone_group based on if id_phone start with 'phone_' or 'phonegroup_'
|
$scheduled_id = $this->internal_scheduled->create($id_user, $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||||
$id_phone_group = null;
|
|
||||||
if ($id_phone)
|
|
||||||
{
|
|
||||||
$id_phone_group = str_starts_with($id_phone, 'phonegroup_') ? mb_substr($id_phone, mb_strlen('phonegroup_')) : null;
|
|
||||||
$id_phone = str_starts_with($id_phone, 'phone_') ? mb_substr($id_phone, mb_strlen('phone_')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$scheduled_id = $this->internal_scheduled->create($id_user, $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
|
||||||
if (!$scheduled_id)
|
if (!$scheduled_id)
|
||||||
{
|
{
|
||||||
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer le Sms.');
|
\FlashMessage\FlashMessage::push('danger', 'Impossible de créer le Sms.');
|
||||||
|
@ -488,7 +473,6 @@ namespace controllers\publics;
|
||||||
$text = $scheduled['text'] ?? false;
|
$text = $scheduled['text'] ?? false;
|
||||||
$id_phone = empty($scheduled['id_phone']) ? null : $scheduled['id_phone'];
|
$id_phone = empty($scheduled['id_phone']) ? null : $scheduled['id_phone'];
|
||||||
$flash = (bool) ($scheduled['flash'] ?? false);
|
$flash = (bool) ($scheduled['flash'] ?? false);
|
||||||
$tag = ($scheduled['tag'] ?? null) ?: null;
|
|
||||||
$numbers = $scheduled['numbers'] ?? [];
|
$numbers = $scheduled['numbers'] ?? [];
|
||||||
$contacts = $scheduled['contacts'] ?? [];
|
$contacts = $scheduled['contacts'] ?? [];
|
||||||
$groups = $scheduled['groups'] ?? [];
|
$groups = $scheduled['groups'] ?? [];
|
||||||
|
@ -666,14 +650,7 @@ namespace controllers\publics;
|
||||||
|
|
||||||
$mms = (bool) count($media_ids);
|
$mms = (bool) count($media_ids);
|
||||||
|
|
||||||
$id_phone_group = null;
|
$this->internal_scheduled->update_for_user($id_user, $id_scheduled, $at, $text, $id_phone, $flash, $mms, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
||||||
if ($id_phone)
|
|
||||||
{
|
|
||||||
$id_phone_group = str_starts_with($id_phone, 'phonegroup_') ? mb_substr($id_phone, mb_strlen('phonegroup_')) : null;
|
|
||||||
$id_phone = str_starts_with($id_phone, 'phone_') ? mb_substr($id_phone, mb_strlen('phone_')) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->internal_scheduled->update_for_user($id_user, $id_scheduled, $at, $text, $id_phone, $id_phone_group, $flash, $mms, $tag, $numbers, $contacts, $groups, $conditional_groups, $media_ids);
|
|
||||||
++$nb_update;
|
++$nb_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,8 @@ namespace controllers\publics;
|
||||||
0 => 'phone_name',
|
0 => 'phone_name',
|
||||||
1 => 'searchable_destination',
|
1 => 'searchable_destination',
|
||||||
2 => 'text',
|
2 => 'text',
|
||||||
3 => 'tag',
|
3 => 'at',
|
||||||
4 => 'at',
|
4 => 'status',
|
||||||
5 => 'status',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$search = $_GET['search']['value'] ?? null;
|
$search = $_GET['search']['value'] ?? null;
|
||||||
|
|
|
@ -75,20 +75,6 @@ namespace controllers\publics;
|
||||||
$setting_value = json_encode($setting_value);
|
$setting_value = json_encode($setting_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
$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'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$update_setting_result = $this->internal_setting->update_for_user($_SESSION['user']['id'], $setting_name, $setting_value);
|
$update_setting_result = $this->internal_setting->update_for_user($_SESSION['user']['id'], $setting_name, $setting_value);
|
||||||
if (false === $update_setting_result)
|
if (false === $update_setting_result)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +82,6 @@ namespace controllers\publics;
|
||||||
|
|
||||||
return $this->redirect(\descartes\Router::url('Setting', 'show'));
|
return $this->redirect(\descartes\Router::url('Setting', 'show'));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$settings = $this->internal_setting->gets_for_user($_SESSION['user']['id']);
|
$settings = $this->internal_setting->gets_for_user($_SESSION['user']['id']);
|
||||||
$_SESSION['user']['settings'] = $settings;
|
$_SESSION['user']['settings'] = $settings;
|
||||||
|
|
|
@ -83,12 +83,6 @@ namespace controllers\publics;
|
||||||
$result = $this->internal_templating->render($template, $data);
|
$result = $this->internal_templating->render($template, $data);
|
||||||
$return = $result;
|
$return = $result;
|
||||||
|
|
||||||
// If we must force GSM 7 alphabet
|
|
||||||
if ((int) ($_SESSION['user']['settings']['force_gsm_alphabet'] ?? false))
|
|
||||||
{
|
|
||||||
$return['result'] = \controllers\internals\Tool::convert_to_gsm0338($return['result']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trim($result['result']))
|
if (!trim($result['result']))
|
||||||
{
|
{
|
||||||
$return['result'] = 'Message vide, il ne sera pas envoyé.';
|
$return['result'] = 'Message vide, il ne sera pas envoyé.';
|
||||||
|
|
|
@ -53,7 +53,7 @@ class Launcher extends AbstractDaemon
|
||||||
|
|
||||||
$this->start_mailer_daemon();
|
$this->start_mailer_daemon();
|
||||||
|
|
||||||
$phones = $this->internal_phone->get_all_for_active_users();
|
$phones = $this->internal_phone->get_all();
|
||||||
$this->start_phones_daemons($phones);
|
$this->start_phones_daemons($phones);
|
||||||
|
|
||||||
sleep(1);
|
sleep(1);
|
||||||
|
|
|
@ -23,6 +23,7 @@ class Phone extends AbstractDaemon
|
||||||
private $read_delay = 20 / 0.5;
|
private $read_delay = 20 / 0.5;
|
||||||
private $read_tick = 0;
|
private $read_tick = 0;
|
||||||
private $msg_queue;
|
private $msg_queue;
|
||||||
|
private $msg_queue_id;
|
||||||
private $webhook_queue;
|
private $webhook_queue;
|
||||||
private $last_message_at;
|
private $last_message_at;
|
||||||
private $phone;
|
private $phone;
|
||||||
|
@ -37,6 +38,7 @@ class Phone extends AbstractDaemon
|
||||||
public function __construct(array $phone)
|
public function __construct(array $phone)
|
||||||
{
|
{
|
||||||
$this->phone = $phone;
|
$this->phone = $phone;
|
||||||
|
$this->msg_queue_id = (int) (QUEUE_ID_PHONE_PREFIX . $this->phone['id']);
|
||||||
|
|
||||||
$name = 'RaspiSMS Daemon Phone ' . $this->phone['id'];
|
$name = 'RaspiSMS Daemon Phone ' . $this->phone['id'];
|
||||||
$logger = new Logger($name);
|
$logger = new Logger($name);
|
||||||
|
@ -85,7 +87,7 @@ class Phone extends AbstractDaemon
|
||||||
//Set last message at to construct time
|
//Set last message at to construct time
|
||||||
$this->last_message_at = microtime(true);
|
$this->last_message_at = microtime(true);
|
||||||
|
|
||||||
$this->msg_queue = msg_get_queue(QUEUE_ID_PHONE);
|
$this->msg_queue = msg_get_queue($this->msg_queue_id);
|
||||||
|
|
||||||
//Instanciate adapter
|
//Instanciate adapter
|
||||||
$adapter_class = $this->phone['adapter'];
|
$adapter_class = $this->phone['adapter'];
|
||||||
|
@ -96,6 +98,10 @@ class Phone extends AbstractDaemon
|
||||||
|
|
||||||
public function on_stop()
|
public function on_stop()
|
||||||
{
|
{
|
||||||
|
//Delete queue on daemon close
|
||||||
|
$this->logger->info('Closing queue : ' . $this->msg_queue_id);
|
||||||
|
msg_remove_queue($this->msg_queue);
|
||||||
|
|
||||||
$this->logger->info('Stopping Phone daemon with pid ' . getmypid());
|
$this->logger->info('Stopping Phone daemon with pid ' . getmypid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,10 +125,8 @@ class Phone extends AbstractDaemon
|
||||||
$maxsize = 409600;
|
$maxsize = 409600;
|
||||||
$message = null;
|
$message = null;
|
||||||
|
|
||||||
// Message type is forged from a prefix concat with the phone ID
|
|
||||||
$message_type = (int) QUEUE_TYPE_SEND_MSG_PREFIX . $this->phone['id'];
|
|
||||||
$error_code = null;
|
$error_code = null;
|
||||||
$success = msg_receive($this->msg_queue, $message_type, $msgtype, $maxsize, $message, true, MSG_IPC_NOWAIT, $error_code); //MSG_IPC_NOWAIT == dont wait if no message found
|
$success = msg_receive($this->msg_queue, QUEUE_TYPE_SEND_MSG, $msgtype, $maxsize, $message, true, MSG_IPC_NOWAIT, $error_code); //MSG_IPC_NOWAIT == dont wait if no message found
|
||||||
|
|
||||||
if (!$success && MSG_ENOMSG !== $error_code)
|
if (!$success && MSG_ENOMSG !== $error_code)
|
||||||
{
|
{
|
||||||
|
@ -144,7 +148,7 @@ class Phone extends AbstractDaemon
|
||||||
//Do message sending
|
//Do message sending
|
||||||
$this->logger->info('Try send message : ' . json_encode($message));
|
$this->logger->info('Try send message : ' . json_encode($message));
|
||||||
|
|
||||||
$response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash'], $message['mms'], $message['tag'], $message['medias'], $message['id_scheduled']);
|
$response = $internal_sended->send($this->adapter, $this->phone['id_user'], $this->phone['id'], $message['text'], $message['destination'], $message['flash'], $message['mms'], $message['medias'], $message['id_scheduled']);
|
||||||
if ($response['error'])
|
if ($response['error'])
|
||||||
{
|
{
|
||||||
$this->logger->error('Failed send message : ' . json_encode($message) . ' with error : ' . $response['error_message']);
|
$this->logger->error('Failed send message : ' . json_encode($message) . ' with error : ' . $response['error_message']);
|
||||||
|
|
|
@ -22,9 +22,8 @@ class Sender extends AbstractDaemon
|
||||||
private $internal_phone;
|
private $internal_phone;
|
||||||
private $internal_scheduled;
|
private $internal_scheduled;
|
||||||
private $internal_received;
|
private $internal_received;
|
||||||
private $internal_sended;
|
|
||||||
private $bdd;
|
private $bdd;
|
||||||
private $msg_queue;
|
private $queues = [];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -46,7 +45,6 @@ class Sender extends AbstractDaemon
|
||||||
{
|
{
|
||||||
//Create the internal controllers
|
//Create the internal controllers
|
||||||
$this->internal_scheduled = new \controllers\internals\Scheduled($this->bdd);
|
$this->internal_scheduled = new \controllers\internals\Scheduled($this->bdd);
|
||||||
$this->internal_sended = new \controllers\internals\Sended($this->bdd);
|
|
||||||
|
|
||||||
//Get smss and transmit order to send to appropriate phone daemon
|
//Get smss and transmit order to send to appropriate phone daemon
|
||||||
$smss_per_scheduled = $this->internal_scheduled->get_smss_to_send();
|
$smss_per_scheduled = $this->internal_scheduled->get_smss_to_send();
|
||||||
|
@ -64,14 +62,15 @@ class Sender extends AbstractDaemon
|
||||||
{
|
{
|
||||||
foreach ($smss_per_scheduled as $id_scheduled => $smss)
|
foreach ($smss_per_scheduled as $id_scheduled => $smss)
|
||||||
{
|
{
|
||||||
//If queue not already exists
|
|
||||||
if (!msg_queue_exists(QUEUE_ID_PHONE) || !isset($this->msg_queue))
|
|
||||||
{
|
|
||||||
$this->msg_queue = msg_get_queue(QUEUE_ID_PHONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($smss as $sms)
|
foreach ($smss as $sms)
|
||||||
{
|
{
|
||||||
|
//If queue not already exists
|
||||||
|
$queue_id = (int) (QUEUE_ID_PHONE_PREFIX . $sms['id_phone']);
|
||||||
|
if (!msg_queue_exists($queue_id) || !isset($queues[$queue_id]))
|
||||||
|
{
|
||||||
|
$this->queues[$queue_id] = msg_get_queue($queue_id);
|
||||||
|
}
|
||||||
|
|
||||||
$msg = [
|
$msg = [
|
||||||
'id_user' => $sms['id_user'],
|
'id_user' => $sms['id_user'],
|
||||||
'id_scheduled' => $sms['id_scheduled'],
|
'id_scheduled' => $sms['id_scheduled'],
|
||||||
|
@ -80,14 +79,11 @@ class Sender extends AbstractDaemon
|
||||||
'destination' => $sms['destination'],
|
'destination' => $sms['destination'],
|
||||||
'flash' => $sms['flash'],
|
'flash' => $sms['flash'],
|
||||||
'mms' => $sms['mms'],
|
'mms' => $sms['mms'],
|
||||||
'tag' => $sms['tag'],
|
|
||||||
'medias' => $sms['medias'] ?? [],
|
'medias' => $sms['medias'] ?? [],
|
||||||
];
|
];
|
||||||
|
|
||||||
// Message type is forged from a prefix concat with the phone ID
|
msg_send($this->queues[$queue_id], QUEUE_TYPE_SEND_MSG, $msg);
|
||||||
$message_type = (int) QUEUE_TYPE_SEND_MSG_PREFIX . $sms['id_phone'];
|
$this->logger->info('Transmit sms send signal to phone ' . $sms['id_phone'] . ' on queue ' . $queue_id . '.');
|
||||||
msg_send($this->msg_queue, $message_type, $msg);
|
|
||||||
$this->logger->info('Transmit sms send signal to phone ' . $sms['id_phone'] . ' on queue ' . QUEUE_ID_PHONE . ' with message type ' . $message_type . '.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->info('Scheduled ' . $id_scheduled . ' treated and deleted.');
|
$this->logger->info('Scheduled ' . $id_scheduled . ' treated and deleted.');
|
||||||
|
@ -103,10 +99,6 @@ class Sender extends AbstractDaemon
|
||||||
|
|
||||||
public function on_stop()
|
public function on_stop()
|
||||||
{
|
{
|
||||||
//Delete queue on daemon close
|
|
||||||
$this->logger->info('Closing queue : ' . $this->msg_queue);
|
|
||||||
msg_remove_queue($this->msg_queue);
|
|
||||||
|
|
||||||
$this->logger->info('Stopping Sender with pid ' . getmypid());
|
$this->logger->info('Stopping Sender with pid ' . getmypid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class AddPhoneLimits 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_limit');
|
|
||||||
$table->addColumn('id_phone', 'integer', ['null' => false])
|
|
||||||
->addColumn('volume', 'integer', ['null' => false])
|
|
||||||
->addColumn('startpoint', 'string', ['null' => false, 'limit' => 254]) # A relative time to use as startpoint for counting volume. See https://www.php.net/manual/en/datetime.formats.relative.php
|
|
||||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP'])
|
|
||||||
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
|
||||||
->addForeignKey('id_phone', 'phone', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
|
||||||
->create();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class AddPhonePriority 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('priority', 'integer', [
|
|
||||||
'null' => false,
|
|
||||||
'default' => 0,
|
|
||||||
'comment' => 'Priority with which the phone will be used. The higher the more prioritary.',
|
|
||||||
'after' => 'name'
|
|
||||||
])
|
|
||||||
->update();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Db\Adapter\MysqlAdapter;
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class CreatePhoneGroup 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()
|
|
||||||
{
|
|
||||||
$this->table('phone_group')
|
|
||||||
->addColumn('id_user', 'integer', ['null' => false])
|
|
||||||
->addColumn('name', 'string', ['null' => false, 'limit' => 100])
|
|
||||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP'])
|
|
||||||
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
|
||||||
->addForeignKey('id_user', 'user', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
|
||||||
->create();
|
|
||||||
|
|
||||||
$this->table('phone_group_phone')
|
|
||||||
->addColumn('id_phone_group', 'integer', ['null' => false])
|
|
||||||
->addColumn('id_phone', 'integer', ['null' => false])
|
|
||||||
->addColumn('created_at', 'timestamp', ['null' => false, 'default' => 'CURRENT_TIMESTAMP'])
|
|
||||||
->addColumn('updated_at', 'timestamp', ['null' => true, 'update' => 'CURRENT_TIMESTAMP'])
|
|
||||||
->addForeignKey('id_phone_group', 'phone_group', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
|
||||||
->addForeignKey('id_phone', 'phone', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
|
||||||
->create();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class AddIdPhoneGroupToScheduled 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()
|
|
||||||
{
|
|
||||||
$this->table('scheduled')
|
|
||||||
->addColumn('id_phone_group', 'integer', ['null' => true, 'default' => null, 'after' => 'id_phone'])
|
|
||||||
->addForeignKey('id_phone_group', 'phone_group', 'id', ['delete' => 'CASCADE', 'update' => 'CASCADE'])
|
|
||||||
->update();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class AddScheduledTag 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('scheduled');
|
|
||||||
$table->addColumn('tag', 'string', ['default' => NULL, 'null' => true, 'limit' => 1000])
|
|
||||||
->update();
|
|
||||||
|
|
||||||
$table = $this->table('sended');
|
|
||||||
$table->addColumn('tag', 'string', ['default' => NULL, 'null' => true, 'limit' => 255])
|
|
||||||
->update();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Phinx\Migration\AbstractMigration;
|
|
||||||
|
|
||||||
class AddReachedLimitPhoneStatus 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->changeColumn('status', 'enum', ['values' => ['available', 'unavailable', 'no_credit', 'limit_reached'], 'default' => 'available']);
|
|
||||||
$table->save();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -91,21 +91,21 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cette fonction permet de faire un retour sous forme de json
|
* Cette fonction permet de faire un retour sous forme de json
|
||||||
* @param array $datas : Les données à retourner sous forme de json
|
* @param array $data : 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
|
* @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
|
* @return ApiController : On retourne l'API controlleur lui meme pour pouvoir chainer
|
||||||
*/
|
*/
|
||||||
public function json ($datas, $secure = true)
|
public function json ($data, $secure = true)
|
||||||
{
|
{
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
if ($secure)
|
if ($secure)
|
||||||
{
|
{
|
||||||
echo htmlspecialchars(json_encode($datas), ENT_NOQUOTES);
|
echo htmlspecialchars(json_encode($data), ENT_NOQUOTES);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
echo json_encode($datas);
|
echo json_encode($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
if (!is_readable($template_path))
|
if (!is_readable($template_path))
|
||||||
{
|
{
|
||||||
throw new exceptions\DescartesExceptionTemplateNotReadable('Template ' . $template_path . ' is not readable.');
|
throw new DescartesTemplateNotReadableException('Template ' . $template_path . ' is not readable.');
|
||||||
}
|
}
|
||||||
|
|
||||||
require $template_path;
|
require $template_path;
|
||||||
|
|
|
@ -144,7 +144,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate IN query params and values
|
* Generate IN query params and values
|
||||||
* @param array $values : Values to generate in array from
|
* @param string $values : Values to generate in array from
|
||||||
* @return array : Array ['QUERY' => string 'IN(...)', 'PARAMS' => [parameters to pass to execute]]
|
* @return array : Array ['QUERY' => string 'IN(...)', 'PARAMS' => [parameters to pass to execute]]
|
||||||
*/
|
*/
|
||||||
protected function _generate_in_from_array ($values)
|
protected function _generate_in_from_array ($values)
|
||||||
|
@ -214,11 +214,6 @@
|
||||||
$operator = '>';
|
$operator = '>';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ('%' == $first_char) :
|
|
||||||
$true_fieldname = mb_substr($fieldname, 1);
|
|
||||||
$operator = 'LIKE';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ('=' == $first_char) :
|
case ('=' == $first_char) :
|
||||||
$true_fieldname = mb_substr($fieldname, 1);
|
$true_fieldname = mb_substr($fieldname, 1);
|
||||||
$operator = '=';
|
$operator = '=';
|
||||||
|
@ -232,11 +227,8 @@
|
||||||
//Protect against injection in fieldname
|
//Protect against injection in fieldname
|
||||||
$true_fieldname = preg_replace('#[^a-zA-Z0-9_]#', '', $true_fieldname);
|
$true_fieldname = preg_replace('#[^a-zA-Z0-9_]#', '', $true_fieldname);
|
||||||
|
|
||||||
// Add a uid to fieldname so we can combine multiple rules on same field
|
$query = '`' . $true_fieldname . '` ' . $operator . ' :where_' . $true_fieldname;
|
||||||
$uid = uniqid();
|
$param = ['where_' . $true_fieldname => $value];
|
||||||
|
|
||||||
$query = '`' . $true_fieldname . '` ' . $operator . ' :where_' . $true_fieldname . '_' . $uid;
|
|
||||||
$param = ['where_' . $true_fieldname . '_' . $uid => $value];
|
|
||||||
|
|
||||||
return ['QUERY' => $query, 'PARAM' => $param];
|
return ['QUERY' => $query, 'PARAM' => $param];
|
||||||
}
|
}
|
||||||
|
@ -366,6 +358,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT COUNT(*) as `count` FROM `" . $table . "` WHERE 1 " . (count($wheres) ? 'AND ' : '') . implode(' AND ', $wheres);
|
$query = "SELECT COUNT(*) as `count` FROM `" . $table . "` WHERE 1 " . (count($wheres) ? 'AND ' : '') . implode(' AND ', $wheres);
|
||||||
|
|
||||||
$query = $this->pdo->prepare($query);
|
$query = $this->pdo->prepare($query);
|
||||||
|
|
||||||
foreach ($params as $label => &$param)
|
foreach ($params as $label => &$param)
|
||||||
|
|
|
@ -72,7 +72,8 @@
|
||||||
protected static function clean_url (string $url)
|
protected static function clean_url (string $url)
|
||||||
{
|
{
|
||||||
$to_remove = parse_url(HTTP_PWD, PHP_URL_PATH);
|
$to_remove = parse_url(HTTP_PWD, PHP_URL_PATH);
|
||||||
$url = mb_strcut($url, $to_remove ? mb_strlen($to_remove) : 0);
|
|
||||||
|
$url = mb_strcut($url, mb_strlen($to_remove));
|
||||||
$url = parse_url($url, PHP_URL_PATH);
|
$url = parse_url($url, PHP_URL_PATH);
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
|
@ -251,7 +252,6 @@
|
||||||
|
|
||||||
$type = $parameter->getType();
|
$type = $parameter->getType();
|
||||||
$type = $type ?? false;
|
$type = $type ?? false;
|
||||||
$type = ($type instanceof \ReflectionNamedType) ? $type->getName() : $type;
|
|
||||||
|
|
||||||
if ($type)
|
if ($type)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,31 +4,24 @@
|
||||||
/*
|
/*
|
||||||
* Define Descartes env
|
* Define Descartes env
|
||||||
*/
|
*/
|
||||||
$http_dir_path = ''; //Path we need to put after servername in url to access app
|
$http_dir_path = '/raspisms'; //Path we need to put after servername in url to access app
|
||||||
$https = $_SERVER['HTTPS'] ?? 0;
|
$http_protocol = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://';
|
||||||
|
$http_server_name = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost';
|
||||||
|
$http_server_port = isset($_SERVER['SERVER_PORT']) ? ($_SERVER['SERVER_PORT'] == 80) ? '' : ':' . $_SERVER['SERVER_PORT'] : '';
|
||||||
|
$https = $_SERVER['HTTPS'] ?? false;
|
||||||
|
|
||||||
// Check for proxy forward
|
if ( !isset($_SERVER['SERVER_PORT']) || ($_SERVER['SERVER_PORT'] == 80 && !$https) || ($_SERVER['SERVER_PORT'] == 443 && $https) )
|
||||||
$forwarded_https = ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? $_SERVER['HTTP_FORWARDED_PROTO'] ?? NULL) == 'https';
|
|
||||||
$forwarded_ssl = ($_SERVER['HTTP_X_FORWARDED_SSL'] ?? NULL) == 'on';
|
|
||||||
$proxy = $forwarded_https || $forwarded_ssl;
|
|
||||||
|
|
||||||
$http_protocol = 'http://';
|
|
||||||
if ($https)
|
|
||||||
{
|
{
|
||||||
$http_protocol = 'https://';
|
$http_server_port = '';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$http_server_port = ':' . $_SERVER['SERVER_PORT'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$http_server_name = $_SERVER['SERVER_NAME'] ?? 'localhost';
|
|
||||||
|
|
||||||
// Check port to only set it if not default port
|
|
||||||
$port = $_SERVER['SERVER_PORT'] ?? '';
|
|
||||||
$port = ($port == 80 && !$https) ? '' : $port;
|
|
||||||
$port = ($port == 443 && $https) ? '' : $port;
|
|
||||||
$port = $proxy ? '' : $port;
|
|
||||||
$http_server_port = $port ? ':' . $port : '';
|
|
||||||
|
|
||||||
|
|
||||||
$pwd = substr(__DIR__, 0, strrpos(__DIR__, '/'));
|
$pwd = substr(__DIR__, 0, strrpos(__DIR__, '/'));
|
||||||
|
$http_pwd = $http_protocol . $http_server_name . $http_server_port . $http_dir_path;
|
||||||
|
|
||||||
|
|
||||||
$env = [
|
$env = [
|
||||||
|
@ -38,6 +31,7 @@
|
||||||
'HTTP_SERVER_NAME' => $http_server_name,
|
'HTTP_SERVER_NAME' => $http_server_name,
|
||||||
'HTTP_SERVER_PORT' => $http_server_port,
|
'HTTP_SERVER_PORT' => $http_server_port,
|
||||||
'PWD' => $pwd,
|
'PWD' => $pwd,
|
||||||
|
'HTTP_PWD' => $http_pwd,
|
||||||
|
|
||||||
//path of back resources
|
//path of back resources
|
||||||
'PWD_CONTROLLER' => $pwd . '/controllers', //Controllers dir
|
'PWD_CONTROLLER' => $pwd . '/controllers', //Controllers dir
|
||||||
|
@ -46,17 +40,22 @@
|
||||||
|
|
||||||
//path of front resources
|
//path of front resources
|
||||||
'PWD_ASSETS' => $pwd . '/assets', //Assets dir
|
'PWD_ASSETS' => $pwd . '/assets', //Assets dir
|
||||||
|
'HTTP_PWD_ASSETS' => $http_pwd . '/assets', //HTTP path of asset dir
|
||||||
|
|
||||||
//images
|
//images
|
||||||
'PWD_IMG' => $pwd . '/assets' . '/img',
|
'PWD_IMG' => $pwd . '/assets' . '/img',
|
||||||
|
'HTTP_PWD_IMG' => $http_pwd . '/assets' . '/img',
|
||||||
|
|
||||||
//css
|
//css
|
||||||
'PWD_CSS' => $pwd . '/assets' . '/css',
|
'PWD_CSS' => $pwd . '/assets' . '/css',
|
||||||
|
'HTTP_PWD_CSS' => $http_pwd . '/assets' . '/css',
|
||||||
|
|
||||||
//javascript
|
//javascript
|
||||||
'PWD_JS' => $pwd . '/assets' . '/js',
|
'PWD_JS' => $pwd . '/assets' . '/js',
|
||||||
|
'HTTP_PWD_JS' => $http_pwd . '/assets' . '/js',
|
||||||
|
|
||||||
//fonts
|
//fonts
|
||||||
'PWD_FONT' => $pwd . '/assets' . '/font',
|
'PWD_FONT' => $pwd . '/assets' . '/font',
|
||||||
|
'HTTP_PWD_FONT' => $http_pwd . '/assets' . '/font',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
$environment = [];
|
$environment = [];
|
||||||
$env = [];
|
$env = [];
|
||||||
|
|
||||||
// Load descartes base env
|
|
||||||
require_once(__DIR__ . '/env.php');
|
require_once(__DIR__ . '/env.php');
|
||||||
$environment = array_merge($environment, $env);
|
$environment = array_merge($environment, $env);
|
||||||
|
|
||||||
|
@ -32,8 +31,11 @@
|
||||||
$environment = array_merge($environment, $env);
|
$environment = array_merge($environment, $env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Define all Descartes constants
|
||||||
|
define_array($environment);
|
||||||
|
|
||||||
### GLOBAL ENV ###
|
### GLOBAL ENV ###
|
||||||
//Load global app env
|
$environment = [];
|
||||||
$env = [];
|
$env = [];
|
||||||
if (file_exists(__DIR__ . '/../env.php'))
|
if (file_exists(__DIR__ . '/../env.php'))
|
||||||
{
|
{
|
||||||
|
@ -41,30 +43,19 @@
|
||||||
$environment = array_merge($environment, $env);
|
$environment = array_merge($environment, $env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
define_array($environment);
|
||||||
|
|
||||||
|
|
||||||
### SPECIFIC ENV ###
|
### SPECIFIC ENV ###
|
||||||
// Load specific environment env
|
$environment = [];
|
||||||
$env = [];
|
$env = [];
|
||||||
if (isset($environment['ENV']) && file_exists(__DIR__ . '/../env.' . $environment['ENV'] . '.php'))
|
|
||||||
|
if (defined('ENV') && file_exists(__DIR__ . '/../env.' . ENV . '.php'))
|
||||||
{
|
{
|
||||||
require_once(__DIR__ . '/../env.' . $environment['ENV'] . '.php');
|
require_once(__DIR__ . '/../env.' . ENV . '.php');
|
||||||
$environment = array_merge($environment, $env);
|
$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);
|
define_array($environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
env.php.dist
36
env.php.dist
|
@ -2,31 +2,28 @@
|
||||||
/*
|
/*
|
||||||
This file define constants and options for the app
|
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 = [
|
||||||
'ENV' => '%APP_ENV%', #env name (probably 'dev' or 'prod'), this value is used to get the env.XXX.php.dist matching env file
|
'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',
|
'SESSION_NAME' => 'raspisms',
|
||||||
'HTTP_DIR_PATH' => $dir_path, // Override default dir path
|
|
||||||
|
|
||||||
//RaspiSMS settings
|
//RaspiSMS settings
|
||||||
'WEBSITE_TITLE' => 'RaspiSMS',
|
'WEBSITE_TITLE' => 'RaspiSMS',
|
||||||
'WEBSITE_DESCRIPTION' => '',
|
'WEBSITE_DESCRIPTION' => '',
|
||||||
'WEBSITE_AUTHOR' => 'Raspberry Pi FR',
|
'WEBSITE_AUTHOR' => 'Raspberry Pi FR',
|
||||||
'PWD_SCRIPTS' => $environment['PWD'] . '/scripts',
|
'PWD_SCRIPTS' => PWD . '/scripts',
|
||||||
'PWD_RECEIVEDS' => $environment['PWD'] . '/receiveds',
|
'PWD_RECEIVEDS' => PWD . '/receiveds',
|
||||||
'HTTP_PWD_SOUND' => $http_pwd . '/assets' . '/sounds',
|
'HTTP_PWD_SOUND' => HTTP_PWD_ASSETS . '/sounds',
|
||||||
'PWD_ADAPTERS' => $environment['PWD'] . '/adapters',
|
'PWD_ADAPTERS' => PWD . '/adapters',
|
||||||
'PWD_DATA' => $environment['PWD'] . '/data',
|
'PWD_DATA' => PWD . '/data',
|
||||||
'HTTP_PWD_DATA' => $http_pwd . '/data',
|
'HTTP_PWD_DATA' => HTTP_PWD . '/data',
|
||||||
'PWD_DATA_PUBLIC' => $environment['PWD'] . '/data/public',
|
'PWD_DATA_PUBLIC' => PWD . '/data/public',
|
||||||
'HTTP_PWD_DATA_PUBLIC' => $http_pwd . '/data/public',
|
'HTTP_PWD_DATA_PUBLIC' => HTTP_PWD . '/data/public',
|
||||||
'PWD_LOGS' => '/var/log/raspisms',
|
'PWD_LOGS' => '/var/log/raspisms',
|
||||||
'PWD_PID' => '/var/run/raspisms',
|
'PWD_PID' => '/var/run/raspisms',
|
||||||
'APP_SECRET' => '%APP_SECRET%',
|
'APP_SECRET' => '%APP_SECRET%',
|
||||||
'ENABLE_COMMAND' => false,
|
'ENABLE_COMMAND' => false,
|
||||||
'ENABLE_ACCOUNT_DELETION' => true,
|
'ENABLE_ACCOUNT_DELETION' => true,
|
||||||
'ENABLE_URL_SHORTENER' => %APP_URL_SHORTENER%,
|
|
||||||
|
|
||||||
//E-mail types
|
//E-mail types
|
||||||
'EMAIL_RESET_PASSWORD' => [
|
'EMAIL_RESET_PASSWORD' => [
|
||||||
|
@ -56,16 +53,17 @@
|
||||||
],
|
],
|
||||||
|
|
||||||
//Phone messages types
|
//Phone messages types
|
||||||
'QUEUE_ID_PHONE' => ftok(__FILE__, 'p'),
|
'QUEUE_ID_PHONE_PREFIX' => ftok(__FILE__, 'p'),
|
||||||
'QUEUE_TYPE_SEND_MSG_PREFIX' => 100,
|
'QUEUE_TYPE_SEND_MSG' => 1,
|
||||||
|
'QUEUE_TYPE_RECEIVE_MSG' => 2,
|
||||||
|
|
||||||
//Queues ids
|
//Queues ids
|
||||||
'QUEUE_ID_WEBHOOK' => ftok(__FILE__, 'w'),
|
'QUEUE_ID_WEBHOOK' => ftok(__FILE__, 'w'),
|
||||||
'QUEUE_TYPE_WEBHOOK' => 100,
|
'QUEUE_TYPE_WEBHOOK' => 3,
|
||||||
|
|
||||||
//Queue email
|
//Queue email
|
||||||
'QUEUE_ID_EMAIL' => ftok(__FILE__, 'e'),
|
'QUEUE_ID_EMAIL' => ftok(__FILE__, 'e'),
|
||||||
'QUEUE_TYPE_EMAIL' => 100,
|
'QUEUE_TYPE_EMAIL' => 3,
|
||||||
|
|
||||||
//User default settings
|
//User default settings
|
||||||
'USER_DEFAULT_SETTINGS' => [
|
'USER_DEFAULT_SETTINGS' => [
|
||||||
|
@ -85,12 +83,6 @@
|
||||||
'alert_quota_limit_reached' => 1,
|
'alert_quota_limit_reached' => 1,
|
||||||
'alert_quota_limit_close' => 0.9,
|
'alert_quota_limit_close' => 0.9,
|
||||||
'hide_menus' => '',
|
'hide_menus' => '',
|
||||||
'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.',
|
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,4 @@
|
||||||
'FROM' => '%APP_MAIL_FROM%',
|
'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%',
|
|
||||||
]
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -84,6 +84,32 @@ namespace models;
|
||||||
return $this->_select('event', ['id_user' => $id_user], 'at', true, $nb_entry);
|
return $this->_select('event', ['id_user' => $id_user], 'at', true, $nb_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets events for a type, since a date and eventually until a date (both included).
|
||||||
|
*
|
||||||
|
* @param int $id_user : User id
|
||||||
|
* @param string $type : Event type we want
|
||||||
|
* @param \DateTime $since : Date to get events since
|
||||||
|
* @param ?\DateTime $until (optional) : Date until wich we want events, if not specified no limit
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_events_by_type_and_date_for_user(int $id_user, string $type, \DateTime $since, ?\DateTime $until = null)
|
||||||
|
{
|
||||||
|
$where = [
|
||||||
|
'id_user' => $id_user,
|
||||||
|
'type' => $type,
|
||||||
|
'>=at' => $since->format('Y-m-d H:i:s'),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (null !== $until)
|
||||||
|
{
|
||||||
|
$where['<=at'] = $until->format('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->_select('event', $where, 'at');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return table name.
|
* Return table name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,36 +13,6 @@ namespace models;
|
||||||
|
|
||||||
class Phone extends StandardModel
|
class Phone extends StandardModel
|
||||||
{
|
{
|
||||||
|
|
||||||
const STATUS_AVAILABLE = 'available';
|
|
||||||
const STATUS_UNAVAILABLE = 'unavailable';
|
|
||||||
const STATUS_NO_CREDIT = 'no_credit';
|
|
||||||
const STATUS_LIMIT_REACHED = 'limit_reached';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return all phones that belongs to active users
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function get_all_for_active_users()
|
|
||||||
{
|
|
||||||
$query = '
|
|
||||||
SELECT phone.*
|
|
||||||
FROM phone
|
|
||||||
LEFT JOIN user
|
|
||||||
ON phone.id_user = user.id
|
|
||||||
WHERE user.status = :status
|
|
||||||
';
|
|
||||||
|
|
||||||
$params = [
|
|
||||||
'status' => \models\User::STATUS_ACTIVE,
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = $this->_run_query($query, $params);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a phone by his name and user.
|
* Return a phone by his name and user.
|
||||||
*
|
*
|
||||||
|
@ -68,48 +38,6 @@ namespace models;
|
||||||
return $this->_select_one('phone', ['name' => $name]);
|
return $this->_select_one('phone', ['name' => $name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of phone limits
|
|
||||||
*
|
|
||||||
* @param int $id_phone : Phone id
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function get_limits(int $id_phone)
|
|
||||||
{
|
|
||||||
return $this->_select('phone_limit', ['id_phone' => $id_phone]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a limit for a phone.
|
|
||||||
*
|
|
||||||
* @param int $id_phone : Phone id
|
|
||||||
* @param int $volume : Limit in volume of SMS
|
|
||||||
* @param string $startpoint : A relative time to use as startpoint for counting volume. See https://www.php.net/manual/en/datetime.formats.relative.php
|
|
||||||
*
|
|
||||||
* @return mixed (bool|int) : False on error, new row id else
|
|
||||||
*/
|
|
||||||
public function insert_phone_limit(int $id_phone, int $volume, string $startpoint)
|
|
||||||
{
|
|
||||||
$success = $this->_insert('phone_limit', ['id_phone' => $id_phone, 'volume' => $volume, 'startpoint' => $startpoint]);
|
|
||||||
|
|
||||||
return $success ? $this->_last_id() : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete limits for a phone
|
|
||||||
*
|
|
||||||
* @param array $id_phone : Phone id
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function delete_phone_limits(int $id_phone)
|
|
||||||
{
|
|
||||||
return $this->_delete('phone_limit', ['id_phone' => $id_phone]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return table name.
|
* Return table name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,123 +0,0 @@
|
||||||
<?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 models;
|
|
||||||
|
|
||||||
class PhoneGroup extends StandardModel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return a list of phone groups for a user.
|
|
||||||
* Add a column nb_phone.
|
|
||||||
*
|
|
||||||
* @param int $id_user : user id
|
|
||||||
* @param ?int $limit : Number of entry to return or null
|
|
||||||
* @param ?int $offset : Number of entry to ignore or null
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function list_for_user(int $id_user, $limit, $offset)
|
|
||||||
{
|
|
||||||
$query = '
|
|
||||||
SELECT pg.*, COUNT(pgp.id) as nb_phone
|
|
||||||
FROM `phone_group` as pg
|
|
||||||
LEFT JOIN phone_group_phone as pgp
|
|
||||||
ON pg.id = pgp.id_phone_group
|
|
||||||
WHERE pg.id_user = :id_user
|
|
||||||
GROUP BY pg.id
|
|
||||||
';
|
|
||||||
|
|
||||||
if (null !== $limit)
|
|
||||||
{
|
|
||||||
$limit = (int) $limit;
|
|
||||||
|
|
||||||
$query .= ' LIMIT ' . $limit;
|
|
||||||
if (null !== $offset)
|
|
||||||
{
|
|
||||||
$offset = (int) $offset;
|
|
||||||
$query .= ' OFFSET ' . $offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$params = [
|
|
||||||
'id_user' => $id_user,
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->_run_query($query, $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a phone group by his name for a user.
|
|
||||||
*
|
|
||||||
* @param int $id_user : User id
|
|
||||||
* @param string $name : Group name
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function get_by_name_for_user(int $id_user, string $name)
|
|
||||||
{
|
|
||||||
return $this->_select_one($this->get_table_name(), ['id_user' => $id_user, 'name' => $name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete relations between phone group and phone for a group.
|
|
||||||
*
|
|
||||||
* @param int $id_phone_group : Group id
|
|
||||||
*
|
|
||||||
* @return int : Number of deleted rows
|
|
||||||
*/
|
|
||||||
public function delete_phone_group_phone_relations(int $id_phone_group)
|
|
||||||
{
|
|
||||||
return $this->_delete('phone_group_phone', ['id_phone_group' => $id_phone_group]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert a relation between a phone group and a phone.
|
|
||||||
*
|
|
||||||
* @param int $id_phone_group : Phone Group id
|
|
||||||
* @param int $id_phone : Phone id
|
|
||||||
*
|
|
||||||
* @return mixed (bool|int) : False on error, new row id else
|
|
||||||
*/
|
|
||||||
public function insert_phone_group_phone_relation(int $id_phone_group, int $id_phone)
|
|
||||||
{
|
|
||||||
$success = (bool) $this->_insert('phone_group_phone', ['id_phone_group' => $id_phone_group, 'id_phone' => $id_phone]);
|
|
||||||
|
|
||||||
return $success ? $this->_last_id() : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get phone groups phones.
|
|
||||||
*
|
|
||||||
* @param int $id_phone_group : Phone Group id
|
|
||||||
*
|
|
||||||
* @return array : Phones of the group
|
|
||||||
*/
|
|
||||||
public function get_phones(int $id_phone_group)
|
|
||||||
{
|
|
||||||
$query = '
|
|
||||||
SELECT *
|
|
||||||
FROM `phone`
|
|
||||||
WHERE id IN (SELECT id_phone FROM `phone_group_phone` WHERE id_phone_group = :id_phone_group)
|
|
||||||
';
|
|
||||||
|
|
||||||
$params = ['id_phone_group' => $id_phone_group];
|
|
||||||
|
|
||||||
return $this->_run_query($query, $params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return table name.
|
|
||||||
*/
|
|
||||||
protected function get_table_name(): string
|
|
||||||
{
|
|
||||||
return 'phone_group';
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -178,42 +178,6 @@ namespace models;
|
||||||
return $this->_select_one('sended', ['id_user' => $id_user, 'uid' => $uid, 'adapter' => $adapter]);
|
return $this->_select_one('sended', ['id_user' => $id_user, 'uid' => $uid, 'adapter' => $adapter]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get number of sended SMS since a date for a phone
|
|
||||||
*
|
|
||||||
* @param int $id_user : User id
|
|
||||||
* @param int $id_phone : Phone id we want the number of sended message for
|
|
||||||
* @param ?\DateTime $since : Date since which we want sended Number. Default to null.
|
|
||||||
* @param ?\DateTime $before : Date up to which we want sended number. Default to null.
|
|
||||||
* @param ?string $tag_like : Tag to filter sms by, this is not a = but a LIKE operator
|
|
||||||
*
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
public function count_since_for_phone_and_user(int $id_user, int $id_phone, ?\DateTime $since = null, ?\DateTime $before = null, ?string $tag_like = null) : int
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'id_user' => $id_user,
|
|
||||||
'id_phone' => $id_phone,
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($since)
|
|
||||||
{
|
|
||||||
$data['>=at'] = $since->format('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($before)
|
|
||||||
{
|
|
||||||
$data['<=at'] = $before->format('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($tag_like)
|
|
||||||
{
|
|
||||||
$data['%tag'] = $tag_like;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->_count('sended', $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of sended SMS for every date since a date for a specific user.
|
* Get number of sended SMS for every date since a date for a specific user.
|
||||||
*
|
*
|
||||||
|
@ -222,14 +186,14 @@ namespace models;
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function count_by_day_and_status_since_for_user($id_user, $date)
|
public function count_by_day_since_for_user($id_user, $date)
|
||||||
{
|
{
|
||||||
$query = "
|
$query = "
|
||||||
SELECT COUNT(id) as nb, status, DATE_FORMAT(at, '%Y-%m-%d') as at_ymd
|
SELECT COUNT(id) as nb, DATE_FORMAT(at, '%Y-%m-%d') as at_ymd
|
||||||
FROM sended
|
FROM sended
|
||||||
WHERE at > :date
|
WHERE at > :date
|
||||||
AND id_user = :id_user
|
AND id_user = :id_user
|
||||||
GROUP BY at_ymd, status
|
GROUP BY at_ymd
|
||||||
";
|
";
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
|
|
|
@ -27,18 +27,6 @@ namespace models;
|
||||||
return $this->_update($this->get_table_name(), ['value' => $value], ['id_user' => $id_user, 'name' => $name]);
|
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.
|
* Return table name.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -13,8 +13,6 @@ namespace models;
|
||||||
|
|
||||||
class SmsStop extends StandardModel
|
class SmsStop extends StandardModel
|
||||||
{
|
{
|
||||||
const SMS_STOP_TAG = 'SMS_STOP';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a smsstop by his number and user.
|
* Return a smsstop by his number and user.
|
||||||
*
|
*
|
||||||
|
|
22
routes.php
22
routes.php
|
@ -76,7 +76,6 @@
|
||||||
'delete' => '/group/delete/{csrf}/',
|
'delete' => '/group/delete/{csrf}/',
|
||||||
'edit' => '/group/edit/',
|
'edit' => '/group/edit/',
|
||||||
'update' => '/group/update/{csrf}/',
|
'update' => '/group/update/{csrf}/',
|
||||||
'preview' => '/group/preview/{id_group}/',
|
|
||||||
'json_list' => '/groups.json/',
|
'json_list' => '/groups.json/',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -89,7 +88,6 @@
|
||||||
'edit' => '/conditional_group/edit/',
|
'edit' => '/conditional_group/edit/',
|
||||||
'update' => '/conditional_group/update/{csrf}/',
|
'update' => '/conditional_group/update/{csrf}/',
|
||||||
'contacts_preview' => '/conditional_group/preview/',
|
'contacts_preview' => '/conditional_group/preview/',
|
||||||
'preview' => '/conditional_group/preview/{id_group}/',
|
|
||||||
'json_list' => '/conditional_groups.json/',
|
'json_list' => '/conditional_groups.json/',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -162,22 +160,6 @@
|
||||||
'add' => '/phone/add/',
|
'add' => '/phone/add/',
|
||||||
'create' => '/phone/create/{csrf}/',
|
'create' => '/phone/create/{csrf}/',
|
||||||
'delete' => '/phone/delete/{csrf}/',
|
'delete' => '/phone/delete/{csrf}/',
|
||||||
'edit' => '/phone/edit/',
|
|
||||||
'update' => '/phone/update/{csrf}/',
|
|
||||||
'update_status' => '/phone/update_status/{csrf}/',
|
|
||||||
'json_list' => '/phones.json/',
|
|
||||||
],
|
|
||||||
|
|
||||||
'PhoneGroup' => [
|
|
||||||
'list' => '/phone_group/',
|
|
||||||
'list_json' => '/phone_group/json/',
|
|
||||||
'add' => '/phone_group/add/',
|
|
||||||
'create' => '/phone_group/create/{csrf}/',
|
|
||||||
'delete' => '/phone_group/delete/{csrf}/',
|
|
||||||
'edit' => '/phone_group/edit/',
|
|
||||||
'update' => '/phone_group/update/{csrf}/',
|
|
||||||
'preview' => '/phone_group/preview/{id_group}/',
|
|
||||||
'json_list' => '/phone_group.json/',
|
|
||||||
],
|
],
|
||||||
|
|
||||||
'Call' => [
|
'Call' => [
|
||||||
|
@ -208,7 +190,6 @@
|
||||||
'/api/list/{entry_type}/',
|
'/api/list/{entry_type}/',
|
||||||
'/api/list/{entry_type}/{page}/',
|
'/api/list/{entry_type}/{page}/',
|
||||||
],
|
],
|
||||||
'get_usage' => '/api/usage/',
|
|
||||||
'post_scheduled' => [
|
'post_scheduled' => [
|
||||||
'/api/scheduled/',
|
'/api/scheduled/',
|
||||||
],
|
],
|
||||||
|
@ -221,9 +202,6 @@
|
||||||
'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}/',
|
||||||
],
|
],
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
<th>Condition</th>
|
<th>Condition</th>
|
||||||
<th>Date de création</th>
|
<th>Date de création</th>
|
||||||
<th>Dernière modification</th>
|
<th>Dernière modification</th>
|
||||||
<th>Preview</th>
|
|
||||||
<th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
|
<th class="checkcolumn"><input type="checkbox" id="check-all"/></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -70,56 +69,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal fade" tabindex="-1" id="preview-text-modal">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
||||||
<h4 class="modal-title">Prévisualisation des contacts</h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
<script>
|
||||||
jQuery(document).ready(function ()
|
jQuery(document).ready(function ()
|
||||||
{
|
{
|
||||||
jQuery('body').on('click', '.preview-button', function (e)
|
|
||||||
{
|
|
||||||
e.preventDefault();
|
|
||||||
var group_id = jQuery(this).attr('data-id-group');
|
|
||||||
|
|
||||||
jQuery.ajax({
|
|
||||||
type: "GET",
|
|
||||||
url: HTTP_PWD + '/conditional_group/preview/' + group_id + '/',
|
|
||||||
success: function (data) {
|
|
||||||
if (!data.success) {
|
|
||||||
jQuery('#preview-text-modal').find('.modal-body').text(data.result);
|
|
||||||
} else {
|
|
||||||
html = '';
|
|
||||||
|
|
||||||
for (contact of data.result)
|
|
||||||
{
|
|
||||||
html += '<div class="preview-contact well">';
|
|
||||||
html += ' <div class="preview-contact-name">' + jQuery.fn.dataTable.render.text().display(contact.name) + '</div>'
|
|
||||||
html += ' <div class="preview-contact-number">' + jQuery.fn.dataTable.render.text().display(contact.number) + '</div>'
|
|
||||||
html += ' <code class="preview-contact-data">' + jQuery.fn.dataTable.render.text().display(contact.data) + '</code>'
|
|
||||||
html += '</div>';
|
|
||||||
console.log(contact);
|
|
||||||
}
|
|
||||||
|
|
||||||
jQuery('#preview-text-modal').find('.modal-body').html(html);
|
|
||||||
}
|
|
||||||
jQuery('#preview-text-modal').modal({'keyboard': true});
|
|
||||||
},
|
|
||||||
dataType: 'json'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
jQuery('.datatable').DataTable({
|
jQuery('.datatable').DataTable({
|
||||||
"pageLength": 25,
|
"pageLength": 25,
|
||||||
"lengthMenu": [[25, 50, 100, 1000, 10000, -1], [25, 50, 100, 1000, 10000, "All"]],
|
"lengthMenu": [[25, 50, 100, 1000, 10000, -1], [25, 50, 100, 1000, 10000, "All"]],
|
||||||
|
@ -145,12 +97,6 @@ jQuery(document).ready(function ()
|
||||||
},
|
},
|
||||||
{data: 'created_at'},
|
{data: 'created_at'},
|
||||||
{data: 'updated_at'},
|
{data: 'updated_at'},
|
||||||
{
|
|
||||||
data: '_',
|
|
||||||
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>';
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
data: 'id',
|
data: 'id',
|
||||||
render: function (data, type, row, meta) {
|
render: function (data, type, row, meta) {
|
||||||
|
@ -160,6 +106,7 @@ jQuery(document).ready(function ()
|
||||||
],
|
],
|
||||||
"deferRender": true
|
"deferRender": true
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -120,29 +120,16 @@
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div class="panel panel-default dashboard-panel-chart">
|
<div class="panel panel-default dashboard-panel-chart">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title"><i class="fa fa-area-chart fa-fw"></i> SMS envoyés depuis le <?= $stats_start_date_formated; ?> : </h3>
|
<h3 class="panel-title"><i class="fa fa-area-chart fa-fw"></i> Activité de la semaine : </h3>
|
||||||
<span style="color: #5CB85C;">SMS envoyés (moyenne = <?php echo $avg_sendeds; ?> par jour).</span><br/>
|
<span style="color: #5CB85C;">SMS envoyés (moyenne = <?php echo $avg_sendeds; ?> par jour).</span><br/>
|
||||||
|
<span style="color: #EDAB4D">SMS reçus (moyenne = <?php echo $avg_receiveds; ?> par jour).</span>
|
||||||
<?php if ($quota_unused) { ?>
|
<?php if ($quota_unused) { ?>
|
||||||
<br/>
|
<br/>
|
||||||
<span style="color: #d9534f">Crédits restants : <?= $quota_unused; ?>.</span>
|
<span style="color: #d9534f">Crédits restants : <?= $quota_unused; ?>.</span>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div id="morris-bar-chart-sended"></div>
|
<div id="morris-area-chart"></div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="panel panel-default dashboard-panel-chart">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title"><i class="fa fa-area-chart fa-fw"></i> SMS reçus depuis le <?= $stats_start_date_formated; ?> : </h3>
|
|
||||||
<span style="color: #EDAB4D">SMS reçus (moyenne = <?php echo $avg_receiveds; ?> par jour).</span>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div id="morris-bar-chart-received"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -257,54 +244,22 @@
|
||||||
<script>
|
<script>
|
||||||
jQuery(document).ready(function()
|
jQuery(document).ready(function()
|
||||||
{
|
{
|
||||||
Morris.Bar({
|
Morris.Area({
|
||||||
element: 'morris-bar-chart-sended',
|
element: 'morris-area-chart',
|
||||||
|
behaveLikeLine: true,
|
||||||
fillOpacity: 0.4,
|
fillOpacity: 0.4,
|
||||||
data: <?php echo $data_bar_chart_sended;?>,
|
data: <?php echo $data_area_chart;?>,
|
||||||
xkey: 'period',
|
xkey: 'period',
|
||||||
parseTime: false,
|
parseTime: false,
|
||||||
ykeys: ['sendeds_failed', 'sendeds_unknown', 'sendeds_delivered'],
|
ykeys: ['sendeds', 'receiveds'],
|
||||||
labels: ['SMS échoués', 'SMS inconnus', 'SMS délivrés'],
|
labels: ['SMS envoyés', 'SMS reçus'],
|
||||||
barColors: ['#D9534F', '#337AB7', '#5CB85C'],
|
lineColors: ['#5CB85C', '#EDAB4D'],
|
||||||
goals: [<?php echo $avg_sendeds; ?>,],
|
goals: [<?php echo $avg_sendeds; ?>, <?php echo $avg_receiveds; ?>],
|
||||||
goalLineColors: ['#5CB85C'],
|
goalLineColors: ['#5CB85C', '#EDAB4D'],
|
||||||
goalStrokeWidth: 2,
|
goalStrokeWidth: 2,
|
||||||
pointSize: 4,
|
pointSize: 4,
|
||||||
hideHover: 'auto',
|
hideHover: 'auto',
|
||||||
resize: true,
|
resize: true
|
||||||
stacked: true,
|
|
||||||
hoverCallback: function (index, options, content, row) {
|
|
||||||
ret = '';
|
|
||||||
for (i = 0; i < options.ykeys.length; i++)
|
|
||||||
{
|
|
||||||
ret += options.labels[i];
|
|
||||||
ret += ' : ';
|
|
||||||
ret += row[options.ykeys[i]];
|
|
||||||
ret += ' (';
|
|
||||||
ret += (row[options.ykeys[i]] / (row.sendeds_total ? row.sendeds_total : 1) * 100).toFixed(2);
|
|
||||||
ret += '%)';
|
|
||||||
ret += "<br/>";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Morris.Bar({
|
|
||||||
element: 'morris-bar-chart-received',
|
|
||||||
fillOpacity: 0.4,
|
|
||||||
data: <?php echo $data_bar_chart_received;?>,
|
|
||||||
xkey: 'period',
|
|
||||||
parseTime: false,
|
|
||||||
ykeys: ['receiveds'],
|
|
||||||
labels: ['SMS reçus'],
|
|
||||||
barColors: ['#EDAB4D'],
|
|
||||||
goals: [<?php echo $avg_receiveds; ?>],
|
|
||||||
goalLineColors: ['#EDAB4D'],
|
|
||||||
goalStrokeWidth: 2,
|
|
||||||
pointSize: 4,
|
|
||||||
hideHover: 'auto',
|
|
||||||
resize: true,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue