add icons for Character groups

This commit is contained in:
coderkun 2014-04-29 14:18:04 +02:00
commit 2d9a41a5fe
3461 changed files with 594457 additions and 0 deletions

View file

@ -0,0 +1,432 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
use Piwik\Common;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugins\MobileMessaging\SMSProvider;
/**
* The MobileMessaging API lets you manage and access all the MobileMessaging plugin features including :
* - manage SMS API credential
* - activate phone numbers
* - check remaining credits
* - send SMS
* @method static \Piwik\Plugins\MobileMessaging\API getInstance()
*/
class API extends \Piwik\Plugin\API
{
const VERIFICATION_CODE_LENGTH = 5;
const SMS_FROM = 'Piwik';
/**
* @param string $provider
* @return SMSProvider
*/
static private function getSMSProviderInstance($provider)
{
return SMSProvider::factory($provider);
}
/**
* determine if SMS API credential are available for the current user
*
* @return bool true if SMS API credential are available for the current user
*/
public function areSMSAPICredentialProvided()
{
Piwik::checkUserHasSomeViewAccess();
$credential = $this->getSMSAPICredential();
return isset($credential[MobileMessaging::API_KEY_OPTION]);
}
private function getSMSAPICredential()
{
$settings = $this->getCredentialManagerSettings();
return array(
MobileMessaging::PROVIDER_OPTION =>
isset($settings[MobileMessaging::PROVIDER_OPTION]) ? $settings[MobileMessaging::PROVIDER_OPTION] : null,
MobileMessaging::API_KEY_OPTION =>
isset($settings[MobileMessaging::API_KEY_OPTION]) ? $settings[MobileMessaging::API_KEY_OPTION] : null,
);
}
/**
* return the SMS API Provider for the current user
*
* @return string SMS API Provider
*/
public function getSMSProvider()
{
$this->checkCredentialManagementRights();
$credential = $this->getSMSAPICredential();
return $credential[MobileMessaging::PROVIDER_OPTION];
}
/**
* set the SMS API credential
*
* @param string $provider SMS API provider
* @param string $apiKey API Key
*
* @return bool true if SMS API credential were validated and saved, false otherwise
*/
public function setSMSAPICredential($provider, $apiKey)
{
$this->checkCredentialManagementRights();
$smsProviderInstance = self::getSMSProviderInstance($provider);
$smsProviderInstance->verifyCredential($apiKey);
$settings = $this->getCredentialManagerSettings();
$settings[MobileMessaging::PROVIDER_OPTION] = $provider;
$settings[MobileMessaging::API_KEY_OPTION] = $apiKey;
$this->setCredentialManagerSettings($settings);
return true;
}
/**
* add phone number
*
* @param string $phoneNumber
*
* @return bool true
*/
public function addPhoneNumber($phoneNumber)
{
Piwik::checkUserIsNotAnonymous();
$phoneNumber = self::sanitizePhoneNumber($phoneNumber);
$verificationCode = "";
for ($i = 0; $i < self::VERIFICATION_CODE_LENGTH; $i++) {
$verificationCode .= mt_rand(0, 9);
}
$smsText = Piwik::translate(
'MobileMessaging_VerificationText',
array(
$verificationCode,
Piwik::translate('General_Settings'),
Piwik::translate('MobileMessaging_SettingsMenu')
)
);
$this->sendSMS($smsText, $phoneNumber, self::SMS_FROM);
$phoneNumbers = $this->retrievePhoneNumbers();
$phoneNumbers[$phoneNumber] = $verificationCode;
$this->savePhoneNumbers($phoneNumbers);
$this->increaseCount(MobileMessaging::PHONE_NUMBER_VALIDATION_REQUEST_COUNT_OPTION, $phoneNumber);
return true;
}
/**
* sanitize phone number
*
* @ignore
* @param string $phoneNumber
* @return string sanitized phone number
*/
public static function sanitizePhoneNumber($phoneNumber)
{
return str_replace(' ', '', $phoneNumber);
}
/**
* send a SMS
*
* @param string $content
* @param string $phoneNumber
* @param string $from
* @return bool true
* @ignore
*/
public function sendSMS($content, $phoneNumber, $from)
{
Piwik::checkUserIsNotAnonymous();
$credential = $this->getSMSAPICredential();
$SMSProvider = self::getSMSProviderInstance($credential[MobileMessaging::PROVIDER_OPTION]);
$SMSProvider->sendSMS(
$credential[MobileMessaging::API_KEY_OPTION],
$content,
$phoneNumber,
$from
);
$this->increaseCount(MobileMessaging::SMS_SENT_COUNT_OPTION, $phoneNumber);
return true;
}
/**
* get remaining credit
*
* @return string remaining credit
*/
public function getCreditLeft()
{
$this->checkCredentialManagementRights();
$credential = $this->getSMSAPICredential();
$SMSProvider = self::getSMSProviderInstance($credential[MobileMessaging::PROVIDER_OPTION]);
return $SMSProvider->getCreditLeft(
$credential[MobileMessaging::API_KEY_OPTION]
);
}
/**
* remove phone number
*
* @param string $phoneNumber
*
* @return bool true
*/
public function removePhoneNumber($phoneNumber)
{
Piwik::checkUserIsNotAnonymous();
$phoneNumbers = $this->retrievePhoneNumbers();
unset($phoneNumbers[$phoneNumber]);
$this->savePhoneNumbers($phoneNumbers);
/**
* Triggered after a phone number has been deleted. This event should be used to clean up any data that is
* related to the now deleted phone number. The ScheduledReports plugin, for example, uses this event to remove
* the phone number from all reports to make sure no text message will be sent to this phone number.
*
* **Example**
*
* public function deletePhoneNumber($phoneNumber)
* {
* $this->unsubscribePhoneNumberFromScheduledReport($phoneNumber);
* }
*
* @param string $phoneNumber The phone number that was just deleted.
*/
Piwik::postEvent('MobileMessaging.deletePhoneNumber', array($phoneNumber));
return true;
}
private function retrievePhoneNumbers()
{
$settings = $this->getCurrentUserSettings();
$phoneNumbers = array();
if (isset($settings[MobileMessaging::PHONE_NUMBERS_OPTION])) {
$phoneNumbers = $settings[MobileMessaging::PHONE_NUMBERS_OPTION];
}
return $phoneNumbers;
}
private function savePhoneNumbers($phoneNumbers)
{
$settings = $this->getCurrentUserSettings();
$settings[MobileMessaging::PHONE_NUMBERS_OPTION] = $phoneNumbers;
$this->setCurrentUserSettings($settings);
}
private function increaseCount($option, $phoneNumber)
{
$settings = $this->getCurrentUserSettings();
$counts = array();
if (isset($settings[$option])) {
$counts = $settings[$option];
}
$countToUpdate = 0;
if (isset($counts[$phoneNumber])) {
$countToUpdate = $counts[$phoneNumber];
}
$counts[$phoneNumber] = $countToUpdate + 1;
$settings[$option] = $counts;
$this->setCurrentUserSettings($settings);
}
/**
* validate phone number
*
* @param string $phoneNumber
* @param string $verificationCode
*
* @return bool true if validation code is correct, false otherwise
*/
public function validatePhoneNumber($phoneNumber, $verificationCode)
{
Piwik::checkUserIsNotAnonymous();
$phoneNumbers = $this->retrievePhoneNumbers();
if (isset($phoneNumbers[$phoneNumber])) {
if ($verificationCode == $phoneNumbers[$phoneNumber]) {
$phoneNumbers[$phoneNumber] = null;
$this->savePhoneNumbers($phoneNumbers);
return true;
}
}
return false;
}
/**
* get phone number list
*
* @return array $phoneNumber => $isValidated
* @ignore
*/
public function getPhoneNumbers()
{
Piwik::checkUserIsNotAnonymous();
$rawPhoneNumbers = $this->retrievePhoneNumbers();
$phoneNumbers = array();
foreach ($rawPhoneNumbers as $phoneNumber => $verificationCode) {
$phoneNumbers[$phoneNumber] = self::isActivated($verificationCode);
}
return $phoneNumbers;
}
/**
* get activated phone number list
*
* @return array $phoneNumber
* @ignore
*/
public function getActivatedPhoneNumbers()
{
Piwik::checkUserIsNotAnonymous();
$phoneNumbers = $this->retrievePhoneNumbers();
$activatedPhoneNumbers = array();
foreach ($phoneNumbers as $phoneNumber => $verificationCode) {
if (self::isActivated($verificationCode)) {
$activatedPhoneNumbers[] = $phoneNumber;
}
}
return $activatedPhoneNumbers;
}
private static function isActivated($verificationCode)
{
return $verificationCode === null;
}
/**
* delete the SMS API credential
*
* @return bool true
*/
public function deleteSMSAPICredential()
{
$this->checkCredentialManagementRights();
$settings = $this->getCredentialManagerSettings();
$settings[MobileMessaging::API_KEY_OPTION] = null;
$this->setCredentialManagerSettings($settings);
return true;
}
private function checkCredentialManagementRights()
{
$this->getDelegatedManagement() ? Piwik::checkUserIsNotAnonymous() : Piwik::checkUserHasSuperUserAccess();
}
private function setUserSettings($user, $settings)
{
Option::set(
$user . MobileMessaging::USER_SETTINGS_POSTFIX_OPTION,
Common::json_encode($settings)
);
}
private function setCurrentUserSettings($settings)
{
$this->setUserSettings(Piwik::getCurrentUserLogin(), $settings);
}
private function setCredentialManagerSettings($settings)
{
$this->setUserSettings($this->getCredentialManagerLogin(), $settings);
}
private function getCredentialManagerLogin()
{
return $this->getDelegatedManagement() ? Piwik::getCurrentUserLogin() : '';
}
private function getUserSettings($user)
{
$optionIndex = $user . MobileMessaging::USER_SETTINGS_POSTFIX_OPTION;
$userSettings = Option::get($optionIndex);
if (empty($userSettings)) {
$userSettings = array();
} else {
$userSettings = Common::json_decode($userSettings, true);
}
return $userSettings;
}
private function getCredentialManagerSettings()
{
return $this->getUserSettings($this->getCredentialManagerLogin());
}
private function getCurrentUserSettings()
{
return $this->getUserSettings(Piwik::getCurrentUserLogin());
}
/**
* Specify if normal users can manage their own SMS API credential
*
* @param bool $delegatedManagement false if SMS API credential only manageable by super admin, true otherwise
*/
public function setDelegatedManagement($delegatedManagement)
{
Piwik::checkUserHasSuperUserAccess();
Option::set(MobileMessaging::DELEGATED_MANAGEMENT_OPTION, $delegatedManagement);
}
/**
* Determine if normal users can manage their own SMS API credential
*
* @return bool false if SMS API credential only manageable by super admin, true otherwise
*/
public function getDelegatedManagement()
{
Piwik::checkUserHasSomeViewAccess();
return Option::get(MobileMessaging::DELEGATED_MANAGEMENT_OPTION) == 'true';
}
}

View file

@ -0,0 +1,19 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
use Exception;
/**
*/
class APIException extends Exception
{
}

View file

@ -0,0 +1,78 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
use Piwik\Common;
use Piwik\IP;
use Piwik\Piwik;
use Piwik\Plugins\LanguagesManager\LanguagesManager;
use Piwik\Plugins\MobileMessaging\SMSProvider;
use Piwik\View;
require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/functions.php';
/**
*
*/
class Controller extends \Piwik\Plugin\ControllerAdmin
{
/*
* Mobile Messaging Settings tab :
* - set delegated management
* - provide & validate SMS API credential
* - add & activate phone numbers
* - check remaining credits
*/
public function index()
{
Piwik::checkUserIsNotAnonymous();
$view = new View('@MobileMessaging/index');
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
$mobileMessagingAPI = API::getInstance();
$view->delegatedManagement = $mobileMessagingAPI->getDelegatedManagement();
$view->credentialSupplied = $mobileMessagingAPI->areSMSAPICredentialProvided();
$view->accountManagedByCurrentUser = $view->isSuperUser || $view->delegatedManagement;
$view->strHelpAddPhone = Piwik::translate('MobileMessaging_Settings_PhoneNumbers_HelpAdd', array(Piwik::translate('General_Settings'), Piwik::translate('MobileMessaging_SettingsMenu')));
if ($view->credentialSupplied && $view->accountManagedByCurrentUser) {
$view->provider = $mobileMessagingAPI->getSMSProvider();
$view->creditLeft = $mobileMessagingAPI->getCreditLeft();
}
$view->smsProviders = SMSProvider::$availableSMSProviders;
// construct the list of countries from the lang files
$countries = array();
foreach (Common::getCountriesList() as $countryCode => $continentCode) {
if (isset(CountryCallingCodes::$countryCallingCodes[$countryCode])) {
$countries[$countryCode] =
array(
'countryName' => \Piwik\Plugins\UserCountry\countryTranslate($countryCode),
'countryCallingCode' => CountryCallingCodes::$countryCallingCodes[$countryCode],
);
}
}
$view->countries = $countries;
$view->defaultCountry = Common::getCountry(
LanguagesManager::getLanguageCodeForCurrentUser(),
true,
IP::getIpFromHeader()
);
$view->phoneNumbers = $mobileMessagingAPI->getPhoneNumbers();
$this->setBasicVariablesView($view);
return $view->render();
}
}

View file

@ -0,0 +1,270 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
/**
*
*/
class CountryCallingCodes
{
// list taken from core/DataFiles/Countries.php
public static $countryCallingCodes = array(
'ad' => '376',
'ae' => '971',
'af' => '93',
'ag' => '1268', // @wikipedia original value: 1 268
'ai' => '1264', // @wikipedia original value: 1 264
'al' => '355',
'am' => '374',
'ao' => '244',
// 'aq' => 'MISSING CODE', // @wikipedia In Antarctica dialing is dependent on the parent country of each base
'ar' => '54',
'as' => '1684', // @wikipedia original value: 1 684
'at' => '43',
'au' => '61',
'aw' => '297',
'ax' => '358',
'az' => '994',
'ba' => '387',
'bb' => '1246', // @wikipedia original value: 1 246
'bd' => '880',
'be' => '32',
'bf' => '226',
'bg' => '359',
'bh' => '973',
'bi' => '257',
'bj' => '229',
'bl' => '590',
'bm' => '1441', // @wikipedia original value: 1 441
'bn' => '673',
'bo' => '591',
'bq' => '5997', // @wikipedia original value: 599 7
'br' => '55',
'bs' => '1242', // @wikipedia original value: 1 242
'bt' => '975',
// 'bv' => 'MISSING CODE',
'bw' => '267',
'by' => '375',
'bz' => '501',
'ca' => '1',
'cc' => '61',
'cd' => '243',
'cf' => '236',
'cg' => '242',
'ch' => '41',
'ci' => '225',
'ck' => '682',
'cl' => '56',
'cm' => '237',
'cn' => '86',
'co' => '57',
'cr' => '506',
'cu' => '53',
'cv' => '238',
'cw' => '5999', // @wikipedia original value: 599 9
'cx' => '61',
'cy' => '357',
'cz' => '420',
'de' => '49',
'dj' => '253',
'dk' => '45',
'dm' => '1767', // @wikipedia original value: 1 767
// 'do' => 'MISSING CODE', // @wikipedia original values: 1 809, 1 829, 1 849
'dz' => '213',
'ec' => '593',
'ee' => '372',
'eg' => '20',
'eh' => '212',
'er' => '291',
'es' => '34',
'et' => '251',
'fi' => '358',
'fj' => '679',
'fk' => '500',
'fm' => '691',
'fo' => '298',
'fr' => '33',
'ga' => '241',
'gb' => '44',
'gd' => '1473', // @wikipedia original value: 1 473
'ge' => '995',
'gf' => '594',
'gg' => '44',
'gh' => '233',
'gi' => '350',
'gl' => '299',
'gm' => '220',
'gn' => '224',
'gp' => '590',
'gq' => '240',
'gr' => '30',
'gs' => '500',
'gt' => '502',
'gu' => '1671', // @wikipedia original value: 1 671
'gw' => '245',
'gy' => '592',
'hk' => '852',
// 'hm' => 'MISSING CODE',
'hn' => '504',
'hr' => '385',
'ht' => '509',
'hu' => '36',
'id' => '62',
'ie' => '353',
'il' => '972',
'im' => '44',
'in' => '91',
'io' => '246',
'iq' => '964',
'ir' => '98',
'is' => '354',
'it' => '39',
'je' => '44',
'jm' => '1876', // @wikipedia original value: 1 876
'jo' => '962',
'jp' => '81',
'ke' => '254',
'kg' => '996',
'kh' => '855',
'ki' => '686',
'km' => '269',
'kn' => '1869', // @wikipedia original value: 1 869
'kp' => '850',
'kr' => '82',
'kw' => '965',
'ky' => '1345', // @wikipedia original value: 1 345
// 'kz' => 'MISSING CODE', // @wikipedia original values: 7 6, 7 7
'la' => '856',
'lb' => '961',
'lc' => '1758', // @wikipedia original value: 1 758
'li' => '423',
'lk' => '94',
'lr' => '231',
'ls' => '266',
'lt' => '370',
'lu' => '352',
'lv' => '371',
'ly' => '218',
'ma' => '212',
'mc' => '377',
'md' => '373',
'me' => '382',
'mf' => '590',
'mg' => '261',
'mh' => '692',
'mk' => '389',
'ml' => '223',
'mm' => '95',
'mn' => '976',
'mo' => '853',
'mp' => '1670', // @wikipedia original value: 1 670
'mq' => '596',
'mr' => '222',
'ms' => '1664', // @wikipedia original value: 1 664
'mt' => '356',
'mu' => '230',
'mv' => '960',
'mw' => '265',
'mx' => '52',
'my' => '60',
'mz' => '258',
'na' => '264',
'nc' => '687',
'ne' => '227',
'nf' => '672',
'ng' => '234',
'ni' => '505',
'nl' => '31',
'no' => '47',
'np' => '977',
'nr' => '674',
'nu' => '683',
'nz' => '64',
'om' => '968',
'pa' => '507',
'pe' => '51',
'pf' => '689',
'pg' => '675',
'ph' => '63',
'pk' => '92',
'pl' => '48',
'pm' => '508',
'pn' => '672',
// 'pr' => 'MISSING CODE', // @wikipedia original values: 1 787, 1 939
'ps' => '970',
'pt' => '351',
'pw' => '680',
'py' => '595',
'qa' => '974',
're' => '262',
'ro' => '40',
'rs' => '381',
'ru' => '7',
'rw' => '250',
'sa' => '966',
'sb' => '677',
'sc' => '248',
'sd' => '249',
'se' => '46',
'sg' => '65',
'sh' => '290',
'si' => '386',
'sj' => '47',
'sk' => '421',
'sl' => '232',
'sm' => '378',
'sn' => '221',
'so' => '252',
'sr' => '597',
'ss' => '211',
'st' => '239',
'sv' => '503',
'sx' => '1721', //@wikipedia original value: 1 721
'sy' => '963',
'sz' => '268',
'tc' => '1649', // @wikipedia original value: 1 649
'td' => '235',
// 'tf' => 'MISSING CODE',
'tg' => '228',
'th' => '66',
// 'ti' => 'MISSING CODE',
'tj' => '992',
'tk' => '690',
'tl' => '670',
'tm' => '993',
'tn' => '216',
'to' => '676',
'tr' => '90',
'tt' => '1868', // @wikipedia original value: 1 868
'tv' => '688',
'tw' => '886',
'tz' => '255',
'ua' => '380',
'ug' => '256',
// 'um' => 'MISSING CODE',
'us' => '1',
'uy' => '598',
'uz' => '998',
// 'va' => 'MISSING CODE', // @wikipedia original values: 39 066, assigned 379
'vc' => '1784', // @wikipedia original value: 1 784
've' => '58',
'vg' => '1284', // @wikipedia original value: 1 284
'vi' => '1340', // @wikipedia original value: 1 340
'vn' => '84',
'vu' => '678',
'wf' => '681',
'ws' => '685',
'ye' => '967',
'yt' => '262',
'za' => '27',
'zm' => '260',
'zw' => '263'
);
}

View file

@ -0,0 +1,158 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
/**
* GSM 03.38 Charset
*
*/
class GSMCharset
{
public static $GSMCharset = array(
// Standard GSM Characters, weight = 1
'@' => 1,
'£' => 1,
'$' => 1,
'¥' => 1,
'è' => 1,
'é' => 1,
'ù' => 1,
'ì' => 1,
'ò' => 1,
'Ç' => 1,
'Ø' => 1,
'ø' => 1,
'Å' => 1,
'å' => 1,
'∆' => 1,
'_' => 1,
'Φ' => 1,
'Γ' => 1,
'Λ' => 1,
'Ω' => 1,
'Π' => 1,
'Ψ' => 1,
'Σ' => 1,
'Θ' => 1,
'Ξ' => 1,
'Æ' => 1,
'æ' => 1,
'ß' => 1,
'É' => 1,
' ' => 1,
'!' => 1,
'"' => 1,
'#' => 1,
'¤' => 1,
'%' => 1,
'&' => 1,
'\'' => 1,
'(' => 1,
')' => 1,
'*' => 1,
'+' => 1,
',' => 1,
'-' => 1,
'.' => 1,
'/' => 1,
'0' => 1,
'1' => 1,
'2' => 1,
'3' => 1,
'4' => 1,
'5' => 1,
'6' => 1,
'7' => 1,
'8' => 1,
'9' => 1,
':' => 1,
';' => 1,
'<' => 1,
'=' => 1,
'>' => 1,
'?' => 1,
'¡' => 1,
'A' => 1,
'B' => 1,
'C' => 1,
'D' => 1,
'E' => 1,
'F' => 1,
'G' => 1,
'H' => 1,
'I' => 1,
'J' => 1,
'K' => 1,
'L' => 1,
'M' => 1,
'N' => 1,
'O' => 1,
'P' => 1,
'Q' => 1,
'R' => 1,
'S' => 1,
'T' => 1,
'U' => 1,
'V' => 1,
'W' => 1,
'X' => 1,
'Y' => 1,
'Z' => 1,
'Ä' => 1,
'Ö' => 1,
'Ñ' => 1,
'Ü' => 1,
'§' => 1,
'¿' => 1,
'a' => 1,
'b' => 1,
'c' => 1,
'd' => 1,
'e' => 1,
'f' => 1,
'g' => 1,
'h' => 1,
'i' => 1,
'j' => 1,
'k' => 1,
'l' => 1,
'm' => 1,
'n' => 1,
'o' => 1,
'p' => 1,
'q' => 1,
'r' => 1,
's' => 1,
't' => 1,
'u' => 1,
'v' => 1,
'w' => 1,
'x' => 1,
'y' => 1,
'z' => 1,
'ä' => 1,
'ö' => 1,
'ñ' => 1,
'ü' => 1,
'à' => 1,
// Extended GSM Characters, weight = 2
'^' => 2,
'{' => 2,
'}' => 2,
'\\' => 2,
'[' => 2,
'~' => 2,
']' => 2,
'|' => 2,
'€' => 2,
);
}

View file

@ -0,0 +1,257 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
use Piwik\Menu\MenuAdmin;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugins\API\API as APIPlugins;
use Piwik\Plugins\MobileMessaging\API as APIMobileMessaging;
use Piwik\Plugins\MobileMessaging\ReportRenderer\ReportRendererException;
use Piwik\Plugins\MobileMessaging\ReportRenderer\Sms;
use Piwik\Plugins\ScheduledReports\API as APIScheduledReports;
use Piwik\View;
/**
*
*/
class MobileMessaging extends \Piwik\Plugin
{
const DELEGATED_MANAGEMENT_OPTION = 'MobileMessaging_DelegatedManagement';
const PROVIDER_OPTION = 'Provider';
const API_KEY_OPTION = 'APIKey';
const PHONE_NUMBERS_OPTION = 'PhoneNumbers';
const PHONE_NUMBER_VALIDATION_REQUEST_COUNT_OPTION = 'PhoneNumberValidationRequestCount';
const SMS_SENT_COUNT_OPTION = 'SMSSentCount';
const DELEGATED_MANAGEMENT_OPTION_DEFAULT = 'false';
const USER_SETTINGS_POSTFIX_OPTION = '_MobileMessagingSettings';
const PHONE_NUMBERS_PARAMETER = 'phoneNumbers';
const MOBILE_TYPE = 'mobile';
const SMS_FORMAT = 'sms';
static private $availableParameters = array(
self::PHONE_NUMBERS_PARAMETER => true,
);
static private $managedReportTypes = array(
self::MOBILE_TYPE => 'plugins/MobileMessaging/images/phone.png'
);
static private $managedReportFormats = array(
self::SMS_FORMAT => 'plugins/MobileMessaging/images/phone.png'
);
static private $availableReports = array(
array(
'module' => 'MultiSites',
'action' => 'getAll',
),
array(
'module' => 'MultiSites',
'action' => 'getOne',
),
);
/**
* @see Piwik\Plugin::getListHooksRegistered
*/
public function getListHooksRegistered()
{
return array(
'Menu.Admin.addItems' => 'addMenu',
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
'ScheduledReports.getReportParameters' => 'getReportParameters',
'ScheduledReports.validateReportParameters' => 'validateReportParameters',
'ScheduledReports.getReportMetadata' => 'getReportMetadata',
'ScheduledReports.getReportTypes' => 'getReportTypes',
'ScheduledReports.getReportFormats' => 'getReportFormats',
'ScheduledReports.getRendererInstance' => 'getRendererInstance',
'ScheduledReports.getReportRecipients' => 'getReportRecipients',
'ScheduledReports.allowMultipleReports' => 'allowMultipleReports',
'ScheduledReports.sendReport' => 'sendReport',
'Template.reportParametersScheduledReports' => 'template_reportParametersScheduledReports',
);
}
function addMenu()
{
MenuAdmin::addEntry('MobileMessaging_SettingsMenu',
array('module' => 'MobileMessaging', 'action' => 'index'),
true,
$order = 12
);
}
/**
* Get JavaScript files
*/
public function getJsFiles(&$jsFiles)
{
$jsFiles[] = "plugins/MobileMessaging/javascripts/MobileMessagingSettings.js";
}
public function getStylesheetFiles(&$stylesheets)
{
$stylesheets[] = "plugins/MobileMessaging/stylesheets/MobileMessagingSettings.less";
}
public function validateReportParameters(&$parameters, $reportType)
{
if (self::manageEvent($reportType)) {
// phone number validation
$availablePhoneNumbers = APIMobileMessaging::getInstance()->getActivatedPhoneNumbers();
$phoneNumbers = $parameters[self::PHONE_NUMBERS_PARAMETER];
foreach ($phoneNumbers as $key => $phoneNumber) {
//when a wrong phone number is supplied we silently discard it
if (!in_array($phoneNumber, $availablePhoneNumbers)) {
unset($phoneNumbers[$key]);
}
}
// 'unset' seems to transform the array to an associative array
$parameters[self::PHONE_NUMBERS_PARAMETER] = array_values($phoneNumbers);
}
}
public function getReportMetadata(&$availableReportMetadata, $reportType, $idSite)
{
if (self::manageEvent($reportType)) {
foreach (self::$availableReports as $availableReport) {
$reportMetadata = APIPlugins::getInstance()->getMetadata(
$idSite,
$availableReport['module'],
$availableReport['action']
);
if ($reportMetadata != null) {
$reportMetadata = reset($reportMetadata);
$availableReportMetadata[] = $reportMetadata;
}
}
}
}
public function getReportTypes(&$reportTypes)
{
$reportTypes = array_merge($reportTypes, self::$managedReportTypes);
}
public function getReportFormats(&$reportFormats, $reportType)
{
if (self::manageEvent($reportType)) {
$reportFormats = array_merge($reportFormats, self::$managedReportFormats);
}
}
public function getReportParameters(&$availableParameters, $reportType)
{
if (self::manageEvent($reportType)) {
$availableParameters = self::$availableParameters;
}
}
public function getRendererInstance(&$reportRenderer, $reportType, $outputType, $report)
{
if (self::manageEvent($reportType)) {
if (\Piwik\Plugin\Manager::getInstance()->isPluginActivated('MultiSites')) {
$reportRenderer = new Sms();
} else {
$reportRenderer = new ReportRendererException(
Piwik::translate('MobileMessaging_MultiSites_Must_Be_Activated')
);
}
}
}
public function allowMultipleReports(&$allowMultipleReports, $reportType)
{
if (self::manageEvent($reportType)) {
$allowMultipleReports = false;
}
}
public function getReportRecipients(&$recipients, $reportType, $report)
{
if (self::manageEvent($reportType)) {
$recipients = $report['parameters'][self::PHONE_NUMBERS_PARAMETER];
}
}
public function sendReport($reportType, $report, $contents, $filename, $prettyDate, $reportSubject, $reportTitle,
$additionalFiles)
{
if (self::manageEvent($reportType)) {
$parameters = $report['parameters'];
$phoneNumbers = $parameters[self::PHONE_NUMBERS_PARAMETER];
// 'All Websites' is one character above the limit, use 'Reports' instead
if ($reportSubject == Piwik::translate('General_MultiSitesSummary')) {
$reportSubject = Piwik::translate('General_Reports');
}
$mobileMessagingAPI = APIMobileMessaging::getInstance();
foreach ($phoneNumbers as $phoneNumber) {
$mobileMessagingAPI->sendSMS(
$contents,
$phoneNumber,
$reportSubject
);
}
}
}
static public function template_reportParametersScheduledReports(&$out)
{
if (Piwik::isUserIsAnonymous()) {
return;
}
$view = new View('@MobileMessaging/reportParametersScheduledReports');
$view->reportType = self::MOBILE_TYPE;
$view->phoneNumbers = APIMobileMessaging::getInstance()->getActivatedPhoneNumbers();
$out .= $view->render();
}
private static function manageEvent($reportType)
{
return in_array($reportType, array_keys(self::$managedReportTypes));
}
function install()
{
$delegatedManagement = Option::get(self::DELEGATED_MANAGEMENT_OPTION);
if (empty($delegatedManagement)) {
Option::set(self::DELEGATED_MANAGEMENT_OPTION, self::DELEGATED_MANAGEMENT_OPTION_DEFAULT);
}
}
function deactivate()
{
// delete all mobile reports
$APIScheduledReports = APIScheduledReports::getInstance();
$reports = $APIScheduledReports->getReports();
foreach ($reports as $report) {
if ($report['type'] == MobileMessaging::MOBILE_TYPE) {
$APIScheduledReports->deleteReport($report['idreport']);
}
}
}
public function uninstall()
{
// currently the UI does not allow to delete a plugin
// when it becomes available, all the MobileMessaging settings (API credentials, phone numbers, etc..) should be removed from the option table
return;
}
}

View file

@ -0,0 +1,71 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging\ReportRenderer;
use Piwik\ReportRenderer;
/**
*
*/
class ReportRendererException extends ReportRenderer
{
private $rendering = "";
function __construct($exception)
{
$this->rendering = $exception;
}
public function setLocale($locale)
{
// nothing to do
}
public function sendToDisk($filename)
{
return ReportRenderer::writeFile(
$filename,
Sms::SMS_FILE_EXTENSION,
$this->rendering
);
}
public function sendToBrowserDownload($filename)
{
ReportRenderer::sendToBrowser(
$filename,
Sms::SMS_FILE_EXTENSION,
Sms::SMS_CONTENT_TYPE,
$this->rendering
);
}
public function sendToBrowserInline($filename)
{
ReportRenderer::inlineToBrowser(
Sms::SMS_CONTENT_TYPE,
$this->rendering
);
}
public function getRenderedReport()
{
return $this->rendering;
}
public function renderFrontPage($reportTitle, $prettyDate, $description, $reportMetadata, $segment)
{
// nothing to do
}
public function renderReport($processedReport)
{
// nothing to do
}
}

View file

@ -0,0 +1,131 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging\ReportRenderer;
use Piwik\Common;
use Piwik\Plugins\MultiSites\API;
use Piwik\ReportRenderer;
use Piwik\Site;
use Piwik\View;
/**
*
*/
class Sms extends ReportRenderer
{
const FLOAT_REGEXP = '/[-+]?[0-9]*[\.,]?[0-9]+/';
const SMS_CONTENT_TYPE = 'text/plain';
const SMS_FILE_EXTENSION = 'sms';
private $rendering = "";
public function setLocale($locale)
{
// nothing to do
}
public function sendToDisk($filename)
{
return ReportRenderer::writeFile($filename, self::SMS_FILE_EXTENSION, $this->rendering);
}
public function sendToBrowserDownload($filename)
{
ReportRenderer::sendToBrowser($filename, self::SMS_FILE_EXTENSION, self::SMS_CONTENT_TYPE, $this->rendering);
}
public function sendToBrowserInline($filename)
{
ReportRenderer::inlineToBrowser(self::SMS_CONTENT_TYPE, $this->rendering);
}
public function getRenderedReport()
{
return $this->rendering;
}
public function renderFrontPage($reportTitle, $prettyDate, $description, $reportMetadata, $segment)
{
// nothing to do
}
public function renderReport($processedReport)
{
$isGoalPluginEnabled = Common::isGoalPluginEnabled();
$prettyDate = $processedReport['prettyDate'];
$reportData = $processedReport['reportData'];
$evolutionMetrics = array();
$multiSitesAPIMetrics = API::getApiMetrics($enhanced = true);
foreach ($multiSitesAPIMetrics as $metricSettings) {
$evolutionMetrics[] = $metricSettings[API::METRIC_EVOLUTION_COL_NAME_KEY];
}
$floatRegex = self::FLOAT_REGEXP;
// no decimal for all metrics to shorten SMS content (keeps the monetary sign for revenue metrics)
$reportData->filter(
'ColumnCallbackReplace',
array(
array_merge(array_keys($multiSitesAPIMetrics), $evolutionMetrics),
function ($value) use ($floatRegex) {
return preg_replace_callback(
$floatRegex,
function ($matches) {
return round($matches[0]);
},
$value
);
}
)
);
// evolution metrics formatting :
// - remove monetary, percentage and white spaces to shorten SMS content
// (this is also needed to be able to test $value != 0 and see if there is an evolution at all in SMSReport.twig)
// - adds a plus sign
$reportData->filter(
'ColumnCallbackReplace',
array(
$evolutionMetrics,
function ($value) use ($floatRegex) {
$matched = preg_match($floatRegex, $value, $matches);
return $matched ? sprintf("%+d", $matches[0]) : $value;
}
)
);
$dataRows = $reportData->getRows();
$reportMetadata = $processedReport['reportMetadata'];
$reportRowsMetadata = $reportMetadata->getRows();
$siteHasECommerce = array();
foreach ($reportRowsMetadata as $rowMetadata) {
$idSite = $rowMetadata->getColumn('idsite');
$siteHasECommerce[$idSite] = Site::isEcommerceEnabledFor($idSite);
}
$view = new View('@MobileMessaging/SMSReport');
$view->assign("isGoalPluginEnabled", $isGoalPluginEnabled);
$view->assign("reportRows", $dataRows);
$view->assign("reportRowsMetadata", $reportRowsMetadata);
$view->assign("prettyDate", $prettyDate);
$view->assign("siteHasECommerce", $siteHasECommerce);
$view->assign("displaySiteName", $processedReport['metadata']['action'] == 'getAll');
// segment
$segment = $processedReport['segment'];
$displaySegment = ($segment != null);
$view->assign("displaySegment", $displaySegment);
if ($displaySegment) {
$view->assign("segmentName", $segment['name']);
}
$this->rendering .= $view->render();
}
}

View file

@ -0,0 +1,174 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging;
use Exception;
use Piwik\Loader;
use Piwik\Piwik;
/**
* The SMSProvider abstract class is used as a base class for SMS provider implementations.
*
*/
abstract class SMSProvider
{
const MAX_GSM_CHARS_IN_ONE_UNIQUE_SMS = 160;
const MAX_GSM_CHARS_IN_ONE_CONCATENATED_SMS = 153;
const MAX_UCS2_CHARS_IN_ONE_UNIQUE_SMS = 70;
const MAX_UCS2_CHARS_IN_ONE_CONCATENATED_SMS = 67;
static public $availableSMSProviders = array(
'Clockwork' => 'You can use <a target="_blank" href="?module=Proxy&action=redirect&url=http://www.clockworksms.com/platforms/piwik/"><img src="plugins/MobileMessaging/images/Clockwork.png"/></a> to send SMS Reports from Piwik.<br/>
<ul>
<li> First, <a target="_blank" href="?module=Proxy&action=redirect&url=http://www.clockworksms.com/platforms/piwik/">get an API Key from Clockwork</a> (Signup is free!)
</li><li> Enter your Clockwork API Key on this page. </li>
</ul>
<br/><em>About Clockwork: </em><ul>
<li>Clockwork gives you fast, reliable high quality worldwide SMS delivery, over 450 networks in every corner of the globe.
</li><li>Cost per SMS message is around ~0.08USD (0.06EUR).
</li><li>Most countries and networks are supported but we suggest you check the latest position on their coverage map <a target="_blank" href="?module=Proxy&action=redirect&url=http://www.clockworksms.com/sms-coverage/">here</a>.
</li>
</ul>
',
);
/**
* Return the SMSProvider associated to the provider name $providerName
*
* @throws Exception If the provider is unknown
* @param string $providerName
* @return \Piwik\Plugins\MobileMessaging\SMSProvider
*/
static public function factory($providerName)
{
$className = __NAMESPACE__ . '\\SMSProvider\\' . $providerName;
try {
Loader::loadClass($className);
return new $className;
} catch (Exception $e) {
throw new Exception(
Piwik::translate(
'MobileMessaging_Exception_UnknownProvider',
array($providerName, implode(', ', array_keys(self::$availableSMSProviders)))
)
);
}
}
/**
* Assert whether a given String contains UCS2 characters
*
* @param string $string
* @return bool true if $string contains UCS2 characters
*/
static public function containsUCS2Characters($string)
{
$GSMCharsetAsString = implode(array_keys(GSMCharset::$GSMCharset));
foreach (self::mb_str_split($string) as $char) {
if (mb_strpos($GSMCharsetAsString, $char) === false) {
return true;
}
}
return false;
}
/**
* Truncate $string and append $appendedString at the end if $string can not fit the
* the $maximumNumberOfConcatenatedSMS.
*
* @param string $string String to truncate
* @param int $maximumNumberOfConcatenatedSMS
* @param string $appendedString
* @return string original $string or truncated $string appended with $appendedString
*/
static public function truncate($string, $maximumNumberOfConcatenatedSMS, $appendedString = 'MobileMessaging_SMS_Content_Too_Long')
{
$appendedString = Piwik::translate($appendedString);
$smsContentContainsUCS2Chars = self::containsUCS2Characters($string);
$maxCharsAllowed = self::maxCharsAllowed($maximumNumberOfConcatenatedSMS, $smsContentContainsUCS2Chars);
$sizeOfSMSContent = self::sizeOfSMSContent($string, $smsContentContainsUCS2Chars);
if ($sizeOfSMSContent <= $maxCharsAllowed) return $string;
$smsContentContainsUCS2Chars = $smsContentContainsUCS2Chars || self::containsUCS2Characters($appendedString);
$maxCharsAllowed = self::maxCharsAllowed($maximumNumberOfConcatenatedSMS, $smsContentContainsUCS2Chars);
$sizeOfSMSContent = self::sizeOfSMSContent($string . $appendedString, $smsContentContainsUCS2Chars);
$sizeToTruncate = $sizeOfSMSContent - $maxCharsAllowed;
$subStrToTruncate = '';
$subStrSize = 0;
$reversedStringChars = array_reverse(self::mb_str_split($string));
for ($i = 0; $subStrSize < $sizeToTruncate; $i++) {
$subStrToTruncate = $reversedStringChars[$i] . $subStrToTruncate;
$subStrSize = self::sizeOfSMSContent($subStrToTruncate, $smsContentContainsUCS2Chars);
}
return preg_replace('/' . preg_quote($subStrToTruncate, '/') . '$/', $appendedString, $string);
}
static private function mb_str_split($string)
{
return preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
}
static private function sizeOfSMSContent($smsContent, $containsUCS2Chars)
{
if ($containsUCS2Chars) return mb_strlen($smsContent, 'UTF-8');
$sizeOfSMSContent = 0;
foreach (self::mb_str_split($smsContent) as $char) {
$sizeOfSMSContent += GSMCharset::$GSMCharset[$char];
}
return $sizeOfSMSContent;
}
static private function maxCharsAllowed($maximumNumberOfConcatenatedSMS, $containsUCS2Chars)
{
$maxCharsInOneUniqueSMS = $containsUCS2Chars ? self::MAX_UCS2_CHARS_IN_ONE_UNIQUE_SMS : self::MAX_GSM_CHARS_IN_ONE_UNIQUE_SMS;
$maxCharsInOneConcatenatedSMS = $containsUCS2Chars ? self::MAX_UCS2_CHARS_IN_ONE_CONCATENATED_SMS : self::MAX_GSM_CHARS_IN_ONE_CONCATENATED_SMS;
$uniqueSMS = $maximumNumberOfConcatenatedSMS == 1;
return $uniqueSMS ?
$maxCharsInOneUniqueSMS :
$maxCharsInOneConcatenatedSMS * $maximumNumberOfConcatenatedSMS;
}
/**
* verify the SMS API credential
*
* @param string $apiKey API Key
* @return bool true if SMS API credential are valid, false otherwise
*/
abstract public function verifyCredential($apiKey);
/**
* get remaining credits
*
* @param string $apiKey API Key
* @return string remaining credits
*/
abstract public function getCreditLeft($apiKey);
/**
* send SMS
*
* @param string $apiKey
* @param string $smsText
* @param string $phoneNumber
* @param string $from
* @return bool true
*/
abstract public function sendSMS($apiKey, $smsText, $phoneNumber, $from);
}

View file

@ -0,0 +1,108 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging\SMSProvider;
use Exception;
use Piwik\Http;
use Piwik\Plugins\MobileMessaging\APIException;
use Piwik\Plugins\MobileMessaging\SMSProvider;
require_once PIWIK_INCLUDE_PATH . "/plugins/MobileMessaging/APIException.php";
/**
*
*/
class Clockwork extends SMSProvider
{
const SOCKET_TIMEOUT = 15;
const BASE_API_URL = 'https://api.mediaburst.co.uk/http';
const CHECK_CREDIT_RESOURCE = '/credit.aspx';
const SEND_SMS_RESOURCE = '/send.aspx';
const ERROR_STRING = 'Error';
const MAXIMUM_FROM_LENGTH = 11;
const MAXIMUM_CONCATENATED_SMS = 3;
public function verifyCredential($apiKey)
{
$this->getCreditLeft($apiKey);
return true;
}
public function sendSMS($apiKey, $smsText, $phoneNumber, $from)
{
$from = substr($from, 0, self::MAXIMUM_FROM_LENGTH);
$smsText = self::truncate($smsText, self::MAXIMUM_CONCATENATED_SMS);
$additionalParameters = array(
'To' => str_replace('+', '', $phoneNumber),
'Content' => $smsText,
'From' => $from,
'Long' => 1,
'MsgType' => self::containsUCS2Characters($smsText) ? 'UCS2' : 'TEXT',
);
$this->issueApiCall(
$apiKey,
self::SEND_SMS_RESOURCE,
$additionalParameters
);
}
private function issueApiCall($apiKey, $resource, $additionalParameters = array())
{
$accountParameters = array(
'Key' => $apiKey,
);
$parameters = array_merge($accountParameters, $additionalParameters);
$url = self::BASE_API_URL
. $resource
. '?' . http_build_query($parameters, '', '&');
$timeout = self::SOCKET_TIMEOUT;
try {
$result = Http::sendHttpRequestBy(
Http::getTransportMethod(),
$url,
$timeout,
$userAgent = null,
$destinationPath = null,
$file = null,
$followDepth = 0,
$acceptLanguage = false,
$acceptInvalidSslCertificate = true
);
} catch (Exception $e) {
$result = self::ERROR_STRING . " " . $e->getMessage();
}
if (strpos($result, self::ERROR_STRING) !== false) {
throw new APIException(
'Clockwork API returned the following error message : ' . $result
);
}
return $result;
}
public function getCreditLeft($apiKey)
{
return $this->issueApiCall(
$apiKey,
self::CHECK_CREDIT_RESOURCE
);
}
}

View file

@ -0,0 +1,34 @@
<?php
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*
*/
namespace Piwik\Plugins\MobileMessaging\SMSProvider;
use Piwik\Plugins\MobileMessaging\SMSProvider;
/**
* Used for testing
*
*/
class StubbedProvider extends SMSProvider
{
public function verifyCredential($apiKey)
{
return true;
}
public function sendSMS($apiKey, $smsText, $phoneNumber, $from)
{
// nothing to do
}
public function getCreditLeft($apiKey)
{
return 1;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

View file

@ -0,0 +1,266 @@
/**
* Piwik - Open source web analytics
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
// TODO when UI stabilized, factorize ajax boiler plate accros MobileMessagingSettings javascript functions
var MobileMessagingSettings = MobileMessagingSettings || (function () {
/************************************************************
* Private data
************************************************************/
var
delegatedManagementSelector = 'input[name=delegatedManagement]',
apiAccountSubmitSelector = '#apiAccountSubmit',
addPhoneNumberSubmitSelector = '#addPhoneNumberSubmit',
providersSelector = '#smsProviders',
providerDescriptionsSelector = '.providerDescription',
apiKeySelector = '#apiKey',
countriesSelector = '#countries',
countryCallingCodeSelector = '#countryCallingCode',
newPhoneNumberSelector = '#newPhoneNumber',
suspiciousPhoneNumberSelector = '#suspiciousPhoneNumber',
validatePhoneNumberSubmitSelector = '.validatePhoneNumberSubmit',
formDescriptionSelector = '.form-description',
removePhoneNumberSubmitSelector = '.removePhoneNumberSubmit',
verificationCodeSelector = '.verificationCode',
phoneNumberSelector = '.phoneNumber',
deleteAcountSelector = '#deleteAccount',
confirmDeleteAccountSelector = '#confirmDeleteAccount',
accountFormSelector = '#accountForm',
displayAccountFormSelector = '#displayAccountForm',
phoneNumberActivatedSelector = '#phoneNumberActivated',
invalidActivationCodeMsgSelector = '#invalidActivationCode',
ajaxErrorsSelector = '#ajaxErrorMobileMessagingSettings',
invalidVerificationCodeAjaxErrorSelector = '#invalidVerificationCodeAjaxError',
ajaxLoadingSelector = '#ajaxLoadingMobileMessagingSettings';
/************************************************************
* Private methods
************************************************************/
function initUIEvents() {
$(delegatedManagementSelector).change(updateDelegatedManagement);
$(apiAccountSubmitSelector).click(updateApiAccount);
$(deleteAcountSelector).click(confirmDeleteApiAccount);
$(displayAccountFormSelector).click(displayAccountForm);
$(addPhoneNumberSubmitSelector).click(addPhoneNumber);
$(newPhoneNumberSelector).keyup(updateSuspiciousPhoneNumberMessage);
$(validatePhoneNumberSubmitSelector).click(validatePhoneNumber);
$(removePhoneNumberSubmitSelector).click(removePhoneNumber);
$(countryCallingCodeSelector).keyup(updateCountry);
$(countriesSelector).change(updateCountryCallingCode);
updateCountryCallingCode();
$(providersSelector).change(updateProviderDescription);
updateProviderDescription();
}
function updateCountry() {
var countryCallingCode = $(countryCallingCodeSelector).val();
if (countryCallingCode != null && countryCallingCode != '') {
var countryToSelect = $(countriesSelector + ' option[value=' + countryCallingCode + ']');
if (countryToSelect.size() > 0) {
countryToSelect.attr('selected', 'selected');
}
else {
$(countriesSelector + ' option:selected').removeAttr('selected');
}
}
}
function displayAccountForm() {
$(accountFormSelector).show();
}
function validatePhoneNumber(event) {
var phoneNumberContainer = $(event.target).parent();
var verificationCodeContainer = phoneNumberContainer.find(verificationCodeSelector);
var verificationCode = verificationCodeContainer.val();
var phoneNumber = phoneNumberContainer.find(phoneNumberSelector).html();
if (verificationCode != null && verificationCode != '') {
var success =
function (response) {
var UI = require('piwik/UI');
var notification = new UI.Notification();
$(phoneNumberActivatedSelector).hide();
if (!response.value) {
var message = $(invalidActivationCodeMsgSelector).html();
notification.show(message, {
context: 'error',
id: 'MobileMessaging_ValidatePhoneNumber',
style: {marginTop: '10px'}
});
}
else {
var message = $(phoneNumberActivatedSelector).html();
notification.show(message, {
context: 'success',
id: 'MobileMessaging_ValidatePhoneNumber',
style: {marginTop: '10px'}
});
$(verificationCodeContainer).remove();
$(phoneNumberContainer).find(validatePhoneNumberSubmitSelector).remove();
$(phoneNumberContainer).find(formDescriptionSelector).remove();
}
notification.scrollToNotification();
};
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams({
module: 'API',
format: 'json',
method: 'MobileMessaging.validatePhoneNumber'
}, 'GET');
ajaxHandler.addParams({phoneNumber: phoneNumber, verificationCode: verificationCode}, 'POST');
ajaxHandler.setCallback(success);
ajaxHandler.setLoadingElement(ajaxLoadingSelector);
ajaxHandler.setErrorElement(invalidVerificationCodeAjaxErrorSelector);
ajaxHandler.send(true);
}
}
function removePhoneNumber(event) {
var phoneNumberContainer = $(event.target).parent();
var phoneNumber = phoneNumberContainer.find(phoneNumberSelector).html();
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams({
module: 'API',
format: 'json',
method: 'MobileMessaging.removePhoneNumber'
}, 'GET');
ajaxHandler.addParams({phoneNumber: phoneNumber}, 'POST');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement(ajaxLoadingSelector);
ajaxHandler.setErrorElement(ajaxErrorsSelector);
ajaxHandler.send(true);
}
function updateSuspiciousPhoneNumberMessage() {
var newPhoneNumber = $(newPhoneNumberSelector).val();
// check if number starts with 0
if ($.trim(newPhoneNumber).lastIndexOf('0', 0) === 0) {
$(suspiciousPhoneNumberSelector).show();
}
else {
$(suspiciousPhoneNumberSelector).hide();
}
}
function addPhoneNumber() {
var newPhoneNumber = $(newPhoneNumberSelector).val();
var countryCallingCode = $(countryCallingCodeSelector).val();
var phoneNumber = '+' + countryCallingCode + newPhoneNumber;
if (newPhoneNumber != null && newPhoneNumber != '') {
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams({
module: 'API',
format: 'json',
method: 'MobileMessaging.addPhoneNumber'
}, 'GET');
ajaxHandler.addParams({phoneNumber: phoneNumber}, 'POST');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement(ajaxLoadingSelector);
ajaxHandler.setErrorElement(ajaxErrorsSelector);
ajaxHandler.send(true);
}
}
function updateCountryCallingCode() {
$(countryCallingCodeSelector).val($(countriesSelector + ' option:selected').val());
}
function updateProviderDescription() {
$(providerDescriptionsSelector).hide();
$('#' + $(providersSelector + ' option:selected').val() + providerDescriptionsSelector).show();
}
function updateDelegatedManagement() {
setDelegatedManagement(getDelegatedManagement());
}
function confirmDeleteApiAccount() {
piwikHelper.modalConfirm(confirmDeleteAccountSelector, {yes: deleteApiAccount});
}
function deleteApiAccount() {
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams({
module: 'API',
format: 'json',
method: 'MobileMessaging.deleteSMSAPICredential'
}, 'GET');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement(ajaxLoadingSelector);
ajaxHandler.setErrorElement(ajaxErrorsSelector);
ajaxHandler.send(true);
}
function updateApiAccount() {
var provider = $(providersSelector + ' option:selected').val();
var apiKey = $(apiKeySelector).val();
if (apiKey != '') {
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams({
module: 'API',
format: 'json',
method: 'MobileMessaging.setSMSAPICredential'
}, 'GET');
ajaxHandler.addParams({provider: provider, apiKey: apiKey}, 'POST');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement(ajaxLoadingSelector);
ajaxHandler.setErrorElement(ajaxErrorsSelector);
ajaxHandler.send(true);
}
}
function setDelegatedManagement(delegatedManagement) {
var ajaxHandler = new ajaxHelper();
ajaxHandler.addParams({
module: 'API',
format: 'json',
method: 'MobileMessaging.setDelegatedManagement'
}, 'GET');
ajaxHandler.addParams({delegatedManagement: delegatedManagement}, 'POST');
ajaxHandler.redirectOnSuccess();
ajaxHandler.setLoadingElement(ajaxLoadingSelector);
ajaxHandler.setErrorElement(ajaxErrorsSelector);
ajaxHandler.send(true);
}
function getDelegatedManagement() {
return $(delegatedManagementSelector + ':checked').val();
}
/************************************************************
* Public data and methods
************************************************************/
return {
/**
* Initialize UI events
*/
initUIEvents: function () {
initUIEvents();
}
};
}());
$(document).ready(function () {
MobileMessagingSettings.initUIEvents();
});

View file

@ -0,0 +1,13 @@
#accountForm ul {
list-style: circle;
margin-left: 17px;
line-height: 1.5em;
}
.providerDescription {
border: 2px dashed #C5BDAD;
border-radius: 16px 16px 16px 16px;
margin-left: 24px;
padding: 11px;
width: 600px;
}

View file

@ -0,0 +1,48 @@
{{ prettyDate }}{% if displaySegment %}, {{ segmentName }}{% endif %}. {% if false %}{% endif %}
{%- if reportRows is empty -%}
{{ 'CoreHome_ThereIsNoDataForThisReport'|translate }}
{%- endif -%}
{%- for rowId, row in reportRows -%}
{%- set rowMetrics=row.columns -%}
{%- set rowMetadata=reportRowsMetadata[rowId].columns -%}
{%- if displaySiteName -%}{{ rowMetrics.label|raw }}: {% endif -%}
{# visits #}
{{- rowMetrics.nb_visits }} {{ 'General_ColumnNbVisits'|translate }}
{%- if rowMetrics.visits_evolution != 0 %} ({{ rowMetrics.visits_evolution }}%){%- endif -%}
{%- if rowMetrics.nb_visits != 0 -%}
{#- actions -#}
, {{ rowMetrics.nb_actions }} {{ 'General_ColumnNbActions'|translate }}
{%- if rowMetrics.actions_evolution != 0 %} ({{ rowMetrics.actions_evolution }}%){%- endif -%}
{%- if isGoalPluginEnabled -%}
{# goal metrics #}
{%- if rowMetrics.nb_conversions != 0 -%}
, {{ 'General_ColumnRevenue'|translate }}: {{ rowMetrics.revenue|raw }}
{%- if rowMetrics.revenue_evolution != 0 %} ({{ rowMetrics.revenue_evolution }}%){%- endif -%}
, {{ rowMetrics.nb_conversions }} {{ 'Goals_GoalConversions'|translate }}
{%- if rowMetrics.nb_conversions_evolution != 0 %} ({{ rowMetrics.nb_conversions_evolution }}%){%- endif -%}
{%- endif -%}
{# eCommerce metrics #}
{%- if siteHasECommerce[rowMetadata.idsite] -%}
, {{ 'General_ProductRevenue'|translate }}: {{ rowMetrics.ecommerce_revenue|raw }}
{%- if rowMetrics.ecommerce_revenue_evolution != 0 %} ({{ rowMetrics.ecommerce_revenue_evolution }}%){%- endif -%}
, {{ rowMetrics.orders }} {{ 'General_EcommerceOrders'|translate }}
{%- if rowMetrics.orders_evolution != 0 %} ({{ rowMetrics.orders_evolution }}%){%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- if not loop.last -%}. {% endif -%}
{%- endfor -%}

View file

@ -0,0 +1,200 @@
{% extends 'admin.twig' %}
{% block content %}
{% if accountManagedByCurrentUser %}
<h2 piwik-enriched-headline
feature-name="{{ 'MobileMessaging_SettingsMenu'|translate }}"
>{{ 'MobileMessaging_Settings_SMSAPIAccount'|translate }}</h2>
{% if credentialSupplied %}
{{ 'MobileMessaging_Settings_CredentialProvided'|translate(provider) }}
{{ creditLeft }}
<br/>
{{ 'MobileMessaging_Settings_UpdateOrDeleteAccount'|translate("<a id='displayAccountForm'>","</a>","<a id='deleteAccount'>","</a>")|raw }}
{% else %}
{{ 'MobileMessaging_Settings_PleaseSignUp'|translate }}
{% endif %}
<div id='accountForm' {% if credentialSupplied %}style='display: none;'{% endif %}>
<br/>
{{ 'MobileMessaging_Settings_SMSProvider'|translate }}
<select id='smsProviders'>
{% for smsProvider, description in smsProviders %}
<option value='{{ smsProvider }}'>
{{ smsProvider }}
</option>
{% endfor %}
</select>
{{ 'MobileMessaging_Settings_APIKey'|translate }}
<input size='25' id='apiKey'/>
<input type='submit' value='{{ 'General_Save'|translate }}' id='apiAccountSubmit' class='submit'/>
{% for smsProvider, description in smsProviders %}
<div class='providerDescription' id='{{ smsProvider }}'>
{{ description|raw }}
</div>
{% endfor %}
</div>
{% endif %}
{% import 'ajaxMacros.twig' as ajax %}
<div style="margin-top:10px">
{{ ajax.errorDiv('ajaxErrorMobileMessagingSettings') }}
</div>
<h2>{{ 'MobileMessaging_PhoneNumbers'|translate }}</h2>
{% if not credentialSupplied %}
{% if accountManagedByCurrentUser %}
{{ 'MobileMessaging_Settings_CredentialNotProvided'|translate }}
{% else %}
{{ 'MobileMessaging_Settings_CredentialNotProvidedByAdmin'|translate }}
{% endif %}
{% else %}
{{ 'MobileMessaging_Settings_PhoneNumbers_Help'|translate }}
<br/>
<br/>
<table style="width:900px;" class="adminTable">
<tbody>
<tr>
<td style="width:480px;">
<strong>{{ 'MobileMessaging_Settings_PhoneNumbers_Add'|translate }}</strong>
<br/><br/>
<span id="suspiciousPhoneNumber" style="display:none;">
{{ 'MobileMessaging_Settings_SuspiciousPhoneNumber'|translate('54184032') }}
<br/><br/>
</span>
+ <input id="countryCallingCode" size="4" maxlength="4"/>&nbsp;
<input id="newPhoneNumber"/>
<input type="submit" value='{{ 'General_Add'|translate }}'
id="addPhoneNumberSubmit"/>
<br/>
<span style=' font-size: 11px;'><span
class="form-description">{{ 'MobileMessaging_Settings_CountryCode'|translate }}</span>
<span class="form-description"
style="margin-left:50px;">{{ 'MobileMessaging_Settings_PhoneNumber'|translate }}</span></span>
<br/><br/>
{{ 'MobileMessaging_Settings_PhoneNumbers_CountryCode_Help'|translate }}
<select id="countries">
{# this is a trick to avoid selecting the first country when no default could be found #}
<option value="">&nbsp;</option>
{% for countryCode, country in countries %}
<option value='{{ country.countryCallingCode }}'
{% if defaultCountry==countryCode %} selected="selected" {% endif %}
>
{{ country.countryName }}
</option>
{% endfor %}
</select>
</td>
<td style="width:220px;">
{% import 'macros.twig' as piwik %}
{{ piwik.inlineHelp(strHelpAddPhone) }}
</td>
</tr>
<tr>
<td colspan="2">
{% if phoneNumbers|length > 0 %}
<br/>
<br/>
<strong>{{ 'MobileMessaging_Settings_ManagePhoneNumbers'|translate }}</strong>
<br/>
<br/>
{% endif %}
{{ ajax.errorDiv('invalidVerificationCodeAjaxError') }}
<div id='phoneNumberActivated' style="display:none;">
{{ 'MobileMessaging_Settings_PhoneActivated'|translate }}
</div>
<div id='invalidActivationCode' style="display:none;">
{{ 'MobileMessaging_Settings_InvalidActivationCode'|translate }}
</div>
<ul>
{% for phoneNumber, validated in phoneNumbers %}
<li>
<span class='phoneNumber'>{{ phoneNumber }}</span>
{% if not validated %}
<input class='verificationCode'/>
<input
type='submit'
value='{{ 'MobileMessaging_Settings_ValidatePhoneNumber'|translate }}'
class='validatePhoneNumberSubmit'
/>
{% endif %}
<input
type='submit'
value='{{ 'General_Remove'|translate }}'
class='removePhoneNumberSubmit'
/>
{% if not validated %}
<br/>
<span class='form-description'>{{ 'MobileMessaging_Settings_VerificationCodeJustSent'|translate }}</span>
{% endif %}
<br/>
<br/>
</li>
{% endfor %}
</ul>
</td>
</tr>
</tbody>
</table>
{% endif %}
{% if isSuperUser %}
<h2>{{ 'MobileMessaging_Settings_SuperAdmin'|translate }}</h2>
<table class='adminTable' style='width:650px;'>
<tr>
<td style="width:400px;">{{ 'MobileMessaging_Settings_LetUsersManageAPICredential'|translate }}</td>
<td style="width:250px;">
<fieldset>
<label>
<input
type='radio'
value='false'
name='delegatedManagement' {% if not delegatedManagement %} checked='checked'{% endif %} />
{{ 'General_No'|translate }}
<br/>
<span class='form-description'>
({{ 'General_Default'|translate }}
) {{ 'MobileMessaging_Settings_LetUsersManageAPICredential_No_Help'|translate }}
</span>
</label>
<br/>
<br/>
<label>
<input
type='radio'
value='true'
name='delegatedManagement' {% if delegatedManagement %} checked='checked'{% endif %} />
{{ 'General_Yes'|translate }}
<br/>
<span class='form-description'>{{ 'MobileMessaging_Settings_LetUsersManageAPICredential_Yes_Help'|translate }}</span>
</label>
</fieldset>
</tr>
</table>
{% endif %}
{{ ajax.loadingDiv('ajaxLoadingMobileMessagingSettings') }}
<div class='ui-confirm' id='confirmDeleteAccount'>
<h2>{{ 'MobileMessaging_Settings_DeleteAccountConfirm'|translate }}</h2>
<input role='yes' type='button' value='{{ 'General_Yes'|translate }}'/>
<input role='no' type='button' value='{{ 'General_No'|translate }}'/>
</div>
{% endblock %}

View file

@ -0,0 +1,61 @@
<tr class='{{ reportType }}'>
<td class="first">
{{ 'MobileMessaging_PhoneNumbers'|translate }}
</td>
<td>
<div class="entityInlineHelp">
{% if phoneNumbers|length == 0 %}
{{ 'MobileMessaging_MobileReport_NoPhoneNumbers'|translate }}
{% else %}
{% for phoneNumber in phoneNumbers %}
<label><input name='phoneNumbers' type='checkbox' id='{{ phoneNumber }}'/>{{ phoneNumber }}</label>
<br/>
{% endfor %}
{{ 'MobileMessaging_MobileReport_AdditionalPhoneNumbers'|translate }}
{% endif %}
<a href='{{ linkTo({'module':"MobileMessaging", 'action': 'index', 'updated':null}) }}'>{{ 'MobileMessaging_MobileReport_MobileMessagingSettingsLink'|translate }}</a>
</div>
<script>
$(function () {
resetReportParametersFunctions ['{{ reportType }}'] = function () {
var reportParameters = {
'phoneNumbers': []
};
updateReportParametersFunctions['{{ reportType }}'](reportParameters);
};
updateReportParametersFunctions['{{ reportType }}'] = function (reportParameters) {
if (reportParameters == null) return;
$('[name=phoneNumbers]').removeProp('checked');
$(reportParameters.phoneNumbers).each(function (index, phoneNumber) {
$('#\\' + phoneNumber).prop('checked', 'checked');
});
$(document).trigger('ScheduledReport.edit', {});
};
getReportParametersFunctions['{{ reportType }}'] = function () {
var parameters = Object();
var selectedPhoneNumbers = $.map(
$('[name=phoneNumbers]').filter(function() {
return !this.disabled && this.checked;
}),
function (phoneNumber) {
return $(phoneNumber).attr('id');
}
);
// returning [''] when no phone numbers are selected avoids the "please provide a value for 'parameters'" error message
parameters.phoneNumbers = selectedPhoneNumbers.length > 0 ? selectedPhoneNumbers : [''];
return parameters;
};
});
</script>
</td>
</tr>