diff options
author | JulienMoumne <julien@piwik.org> | 2012-08-14 00:26:46 +0400 |
---|---|---|
committer | JulienMoumne <julien@piwik.org> | 2012-08-14 00:26:46 +0400 |
commit | 7427003ab87ef41d1b1f23365480cf8c8bb11242 (patch) | |
tree | 203b52fb8bcb69f2b4b999cb828dc3386c29e8ae /plugins | |
parent | 4931b9809c69947a16b67954802cecd5140bdfad (diff) |
refs #2708
* fixing a bug in ''Piwik::getPrettyValue()'' where a revenue evolution would be prettified like so: ''$ 100%''
* fixing a bug happening when no data is available for the selected day
* when MultiSites plugin is deactivated, invite user via SMS to activate it back
* SMS API accounts are now managed using an API key instead of a username and a password
* adding ''[too long]'' at the end of the SMS content when it reaches the maximum length allowed by the SMS API
* support for UCS-2 characters
* Mediaburst rebranded to Clockwork
* various UI improvements based on comment:31:ticket:2708
* PDFReport.generateReport now supports $outputType=3 : output report in browser
* removing non-libre select-to-autocomplete jQuery plugin
* tracking count of phone number validation requests and SMS sent
* SMS content now contains CoreHome_ThereIsNoDataForThisReport when applicable
* setting SMS From with General_Reports when configured report is MultiSites_getAll
* adding Clockwork description
TODO
* using POST instead of GET to send SMS to go around a Clockwork limitation
git-svn-id: http://dev.piwik.org/svn/trunk@6727 59fd770c-687e-43c8-a1e3-f5a4ff64c105
Diffstat (limited to 'plugins')
20 files changed, 683 insertions, 463 deletions
diff --git a/plugins/MobileMessaging/API.php b/plugins/MobileMessaging/API.php index 31a32bedab..1a9ca47d17 100644 --- a/plugins/MobileMessaging/API.php +++ b/plugins/MobileMessaging/API.php @@ -55,9 +55,7 @@ class Piwik_MobileMessaging_API Piwik::checkUserIsNotAnonymous(); $credential = $this->getSMSAPICredential(); - return - isset($credential[Piwik_MobileMessaging::USERNAME_OPTION]) - && !empty($credential[Piwik_MobileMessaging::USERNAME_OPTION]); + return isset($credential[Piwik_MobileMessaging::API_KEY_OPTION]); } private function getSMSAPICredential() @@ -66,26 +64,12 @@ class Piwik_MobileMessaging_API return array( Piwik_MobileMessaging::PROVIDER_OPTION => isset($settings[Piwik_MobileMessaging::PROVIDER_OPTION]) ? $settings[Piwik_MobileMessaging::PROVIDER_OPTION] : null, - Piwik_MobileMessaging::USERNAME_OPTION => - isset($settings[Piwik_MobileMessaging::USERNAME_OPTION]) ? $settings[Piwik_MobileMessaging::USERNAME_OPTION] : null, - Piwik_MobileMessaging::PASSWORD_OPTION => - isset($settings[Piwik_MobileMessaging::PASSWORD_OPTION]) ? $settings[Piwik_MobileMessaging::PASSWORD_OPTION] : null, + Piwik_MobileMessaging::API_KEY_OPTION => + isset($settings[Piwik_MobileMessaging::API_KEY_OPTION]) ? $settings[Piwik_MobileMessaging::API_KEY_OPTION] : null, ); } /** - * return the username of the SMS API account for the current user - * - * @return string username of the SMS API account - */ - public function getAPIUsername() - { - $this->checkCredentialManagementRights(); - $credential = $this->getSMSAPICredential(); - return $credential[Piwik_MobileMessaging::USERNAME_OPTION]; - } - - /** * return the SMS API Provider for the current user * * @return string SMS API Provider @@ -101,23 +85,21 @@ class Piwik_MobileMessaging_API * set the SMS API credential * * @param string $provider SMS API provider - * @param string $username SMS API username - * @param string $password SMS API password + * @param string $apiKey API Key * * @return bool true if SMS API credential were validated and saved, false otherwise */ - public function setSMSAPICredential($provider, $username, $password) + public function setSMSAPICredential($provider, $apiKey) { $this->checkCredentialManagementRights(); $smsProviderInstance = self::getSMSProviderInstance($provider); - $smsProviderInstance->verifyCredential($username, $password); + $smsProviderInstance->verifyCredential($apiKey); $settings = $this->getCredentialManagerSettings(); $settings[Piwik_MobileMessaging::PROVIDER_OPTION] = $provider; - $settings[Piwik_MobileMessaging::USERNAME_OPTION] = $username; - $settings[Piwik_MobileMessaging::PASSWORD_OPTION] = $password; + $settings[Piwik_MobileMessaging::API_KEY_OPTION] = $apiKey; $this->setCredentialManagerSettings($settings); @@ -141,7 +123,14 @@ class Piwik_MobileMessaging_API $verificationCode .= rand(0,9); } - $smsText = Piwik_Translate('MobileMessaging_VerificationText', $verificationCode); + $smsText = Piwik_Translate( + 'MobileMessaging_VerificationText', + array( + $verificationCode, + Piwik_Translate('UserSettings_SubmenuSettings'), + Piwik_Translate('MobileMessaging_SettingsMenu') + ) + ); $this->sendSMS($smsText, $phoneNumber, self::SMS_FROM); @@ -149,6 +138,8 @@ class Piwik_MobileMessaging_API $phoneNumbers[$phoneNumber] = $verificationCode; $this->savePhoneNumbers($phoneNumbers); + $this->increaseCount(Piwik_MobileMessaging::PHONE_NUMBER_VALIDATION_REQUEST_COUNT_OPTION, $phoneNumber); + return true; } @@ -166,13 +157,14 @@ class Piwik_MobileMessaging_API $credential = $this->getSMSAPICredential(); $SMSProvider = self::getSMSProviderInstance($credential[Piwik_MobileMessaging::PROVIDER_OPTION]); $SMSProvider->sendSMS( - $credential[Piwik_MobileMessaging::USERNAME_OPTION], - $credential[Piwik_MobileMessaging::PASSWORD_OPTION], + $credential[Piwik_MobileMessaging::API_KEY_OPTION], $content, $phoneNumber, $from ); + $this->increaseCount(Piwik_MobileMessaging::SMS_SENT_COUNT_OPTION, $phoneNumber); + return true; } @@ -188,8 +180,7 @@ class Piwik_MobileMessaging_API $credential = $this->getSMSAPICredential(); $SMSProvider = self::getSMSProviderInstance($credential[Piwik_MobileMessaging::PROVIDER_OPTION]); return $SMSProvider->getCreditLeft( - $credential[Piwik_MobileMessaging::USERNAME_OPTION], - $credential[Piwik_MobileMessaging::PASSWORD_OPTION] + $credential[Piwik_MobileMessaging::API_KEY_OPTION] ); } @@ -236,6 +227,7 @@ class Piwik_MobileMessaging_API { $reportParameters[Piwik_MobileMessaging::PHONE_NUMBERS_PARAMETER] = $updatedPhoneNumbers; + // note: reports can end up without any recipients $pdfReportsAPIInstance->updateReport( $report['idreport'], $report['idsite'], @@ -275,6 +267,38 @@ class Piwik_MobileMessaging_API $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); + } + + private function saveSMSSentCount($smsSentCount) + { + $settings = $this->getCurrentUserSettings(); + + $settings[Piwik_MobileMessaging::SMS_SENT_COUNT_OPTION] = $smsSentCount; + + $this->setCurrentUserSettings($settings); + } + /** * validate phone number * @@ -363,8 +387,7 @@ class Piwik_MobileMessaging_API $settings = $this->getCredentialManagerSettings(); - $settings[Piwik_MobileMessaging::USERNAME_OPTION] = null; - $settings[Piwik_MobileMessaging::PASSWORD_OPTION] = null; + $settings[Piwik_MobileMessaging::API_KEY_OPTION] = null; $this->setCredentialManagerSettings($settings); diff --git a/plugins/MobileMessaging/Controller.php b/plugins/MobileMessaging/Controller.php index 619c39b7a0..4c3606c61b 100644 --- a/plugins/MobileMessaging/Controller.php +++ b/plugins/MobileMessaging/Controller.php @@ -41,7 +41,6 @@ class Piwik_MobileMessaging_Controller extends Piwik_Controller_Admin if($view->credentialSupplied && $view->accountManagedByCurrentUser) { $view->provider = $mobileMessagingAPI->getSMSProvider(); - $view->APIUsername = $mobileMessagingAPI->getAPIUsername(); $view->creditLeft = $mobileMessagingAPI->getCreditLeft(); } diff --git a/plugins/MobileMessaging/CountryCallingCodes.php b/plugins/MobileMessaging/CountryCallingCodes.php index 7313b5937e..1e260c4c46 100644 --- a/plugins/MobileMessaging/CountryCallingCodes.php +++ b/plugins/MobileMessaging/CountryCallingCodes.php @@ -16,7 +16,6 @@ */ class Piwik_MobileMessaging_CountryCallingCodes { - // @review is this the correct way to store calling codes or should we use GLOBALS like in core/DataFiles/Countries.php? // list taken from core/DataFiles/Countries.php public static $countryCallingCodes = array( 'ad' => '376', diff --git a/plugins/MobileMessaging/GSMCharset.php b/plugins/MobileMessaging/GSMCharset.php new file mode 100644 index 0000000000..cbd2980676 --- /dev/null +++ b/plugins/MobileMessaging/GSMCharset.php @@ -0,0 +1,160 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + * + * @category Piwik_Plugins + * @package Piwik_MobileMessaging + */ + +/** + * GSM 03.38 Charset + * + * @package Piwik_MobileMessaging + */ +class Piwik_MobileMessaging_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, + ); +} diff --git a/plugins/MobileMessaging/MobileMessaging.php b/plugins/MobileMessaging/MobileMessaging.php index e52c2cfdc4..ba79a349d8 100644 --- a/plugins/MobileMessaging/MobileMessaging.php +++ b/plugins/MobileMessaging/MobileMessaging.php @@ -18,9 +18,10 @@ class Piwik_MobileMessaging extends Piwik_Plugin { const DELEGATED_MANAGEMENT_OPTION = 'MobileMessaging_DelegatedManagement'; const PROVIDER_OPTION = 'Provider'; - const USERNAME_OPTION = 'Username'; - const PASSWORD_OPTION = 'Password'; + 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'; @@ -111,7 +112,6 @@ class Piwik_MobileMessaging extends Piwik_Plugin $jsFiles = &$notification->getNotificationObject(); $jsFiles[] = "plugins/MobileMessaging/scripts/MobileMessagingSettings.js"; - $jsFiles[] = "plugins/MobileMessaging/scripts/jquery.select-to-autocomplete.js"; // @review should this go in the LEGALNOTICE file ? } /** @@ -129,7 +129,7 @@ class Piwik_MobileMessaging extends Piwik_Plugin $phoneNumbers = $parameters[self::PHONE_NUMBERS_PARAMETER]; foreach($phoneNumbers as $key => $phoneNumber) { - //@review when a wrong phone number is supplied we silently discard it, should an exception be raised? + //when a wrong phone number is supplied we silently discard it if(!in_array($phoneNumber, $availablePhoneNumbers)) { unset($phoneNumbers[$key]); @@ -160,9 +160,12 @@ class Piwik_MobileMessaging extends Piwik_Plugin $availableReport['module'], $availableReport['action'] ); - $reportMetadata = reset($reportMetadata); - $availableReportMetadata[] = $reportMetadata; + if($reportMetadata != null) + { + $reportMetadata = reset($reportMetadata); + $availableReportMetadata[] = $reportMetadata; + } } } } @@ -208,7 +211,17 @@ class Piwik_MobileMessaging extends Piwik_Plugin if(self::manageEvent($notification)) { $reportRenderer = &$notification->getNotificationObject(); - $reportRenderer = new Piwik_MobileMessaging_ReportRenderer_Sms(); + + if(Piwik_PluginsManager::getInstance()->isPluginActivated('MultiSites')) + { + $reportRenderer = new Piwik_MobileMessaging_ReportRenderer_Sms(); + } + else + { + $reportRenderer = new Piwik_MobileMessaging_ReportRenderer_Exception( + Piwik_Translate('MobileMessaging_MultiSites_Must_Be_Activated') + ); + } } } @@ -245,19 +258,27 @@ class Piwik_MobileMessaging extends Piwik_Plugin { $notificationInfo = $notification->getNotificationInfo(); $report = $notificationInfo[Piwik_PDFReports_API::REPORT_KEY]; - $websiteName = $notificationInfo[Piwik_PDFReports_API::WEBSITE_NAME_KEY]; $contents = $notificationInfo[Piwik_PDFReports_API::REPORT_CONTENT_KEY]; $parameters = $report['parameters']; $phoneNumbers = $parameters[self::PHONE_NUMBERS_PARAMETER]; + if(in_array('MultiSites_getAll', $report['reports'])) + { + $from = Piwik_Translate('General_Reports'); + } + else + { + $from = $notificationInfo[Piwik_PDFReports_API::WEBSITE_NAME_KEY]; + } + $mobileMessagingAPI = Piwik_MobileMessaging_API::getInstance(); foreach($phoneNumbers as $phoneNumber) { $mobileMessagingAPI->sendSMS( $contents, $phoneNumber, - $websiteName + $from ); } } @@ -291,7 +312,6 @@ class Piwik_MobileMessaging extends Piwik_Plugin } } - //@review should we also delete the plugin settings (API credentials, phone numbers) located in table piwik_option? function deactivate() { // delete all mobile reports @@ -306,4 +326,11 @@ class Piwik_MobileMessaging extends Piwik_Plugin } } } + + 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; + } } diff --git a/plugins/MobileMessaging/ReportRenderer/Exception.php b/plugins/MobileMessaging/ReportRenderer/Exception.php new file mode 100644 index 0000000000..7e9df15dc1 --- /dev/null +++ b/plugins/MobileMessaging/ReportRenderer/Exception.php @@ -0,0 +1,67 @@ +<?php +/** + * Piwik - Open source web analytics + * + * @link http://piwik.org + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later + * @version $Id$ + * + * @category Piwik_Plugins + * @package Piwik_MobileMessaging_ReportRenderer + */ + +/** + * + * @package Piwik_MobileMessaging_ReportRenderer + */ +class Piwik_MobileMessaging_ReportRenderer_Exception extends Piwik_ReportRenderer +{ + private $rendering = ""; + + function __construct($exception) + { + $this->rendering = $exception; + } + + public function setLocale($locale) + { + // nothing to do + } + + public function sendToDisk($filename) + { + return Piwik_ReportRenderer::writeFile( + $filename, + Piwik_MobileMessaging_ReportRenderer_Sms::SMS_FILE_EXTENSION, + $this->rendering + ); + } + + public function sendToBrowserDownload($filename) + { + Piwik_ReportRenderer::sendToBrowser( + $filename, + Piwik_MobileMessaging_ReportRenderer_Sms::SMS_FILE_EXTENSION, + Piwik_MobileMessaging_ReportRenderer_Sms::SMS_CONTENT_TYPE, + $this->rendering + ); + } + + public function sendToBrowserInline($filename) + { + Piwik_ReportRenderer::inlineToBrowser( + Piwik_MobileMessaging_ReportRenderer_Sms::SMS_CONTENT_TYPE, + $this->rendering + ); + } + + public function renderFrontPage($websiteName, $prettyDate, $description, $reportMetadata) + { + // nothing to do + } + + public function renderReport($processedReport) + { + // nothing to do + } +} diff --git a/plugins/MobileMessaging/ReportRenderer/Sms.php b/plugins/MobileMessaging/ReportRenderer/Sms.php index 5f3662fc59..88f64aa81a 100644 --- a/plugins/MobileMessaging/ReportRenderer/Sms.php +++ b/plugins/MobileMessaging/ReportRenderer/Sms.php @@ -18,6 +18,9 @@ const FLOAT_REGEXP = '/[-+]?[0-9]*[\.,]?[0-9]+/'; */ class Piwik_MobileMessaging_ReportRenderer_Sms extends Piwik_ReportRenderer { + const SMS_CONTENT_TYPE = 'text/plain'; + const SMS_FILE_EXTENSION = 'sms'; + private $rendering = ""; public function setLocale($locale) @@ -27,12 +30,17 @@ class Piwik_MobileMessaging_ReportRenderer_Sms extends Piwik_ReportRenderer public function sendToDisk($filename) { - return Piwik_ReportRenderer::writeFile($filename, 'sms', $this->rendering); + return Piwik_ReportRenderer::writeFile($filename, self::SMS_FILE_EXTENSION, $this->rendering); } public function sendToBrowserDownload($filename) { - Piwik_ReportRenderer::sendToBrowser($filename, 'sms', 'text/plain', $this->rendering); + Piwik_ReportRenderer::sendToBrowser($filename, self::SMS_FILE_EXTENSION, self::SMS_CONTENT_TYPE, $this->rendering); + } + + public function sendToBrowserInline($filename) + { + Piwik_ReportRenderer::inlineToBrowser(self::SMS_CONTENT_TYPE, $this->rendering); } public function renderFrontPage($websiteName, $prettyDate, $description, $reportMetadata) diff --git a/plugins/MobileMessaging/SMSProvider.php b/plugins/MobileMessaging/SMSProvider.php index 1e205de0de..26faf10403 100644 --- a/plugins/MobileMessaging/SMSProvider.php +++ b/plugins/MobileMessaging/SMSProvider.php @@ -18,8 +18,13 @@ */ abstract class Piwik_MobileMessaging_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( - 'Mediaburst', + 'Clockwork' => 'MobileMessaging_SMSProvider_Description_Clockwork', ); /** @@ -41,38 +46,121 @@ abstract class Piwik_MobileMessaging_SMSProvider throw new Exception( Piwik_TranslateException( 'MobileMessaging_Exception_UnknownProvider', - array($name, implode(', ', self::$availableSMSProviders)) + array($name, 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(Piwik_MobileMessaging_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 += Piwik_MobileMessaging_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 $username SMS API username - * @param string $password SMS API password + * @param string $apiKey API Key * @return bool true if SMS API credential are valid, false otherwise */ - abstract public function verifyCredential($username, $password); + abstract public function verifyCredential($apiKey); /** * get remaining credits * - * @param string $username SMS API username - * @param string $password SMS API password + * @param string $apiKey API Key * @return string remaining credits */ - abstract public function getCreditLeft($username, $password); + abstract public function getCreditLeft($apiKey); /** * send SMS * - * @param string $username - * @param string $password + * @param string $apiKey * @param string $smsText * @param string $phoneNumber * @return bool true */ - abstract public function sendSMS($username, $password, $smsText, $phoneNumber, $from); + abstract public function sendSMS($apiKey, $smsText, $phoneNumber, $from); } diff --git a/plugins/MobileMessaging/SMSProvider/Mediaburst.php b/plugins/MobileMessaging/SMSProvider/Clockwork.php index 71cf280cf2..91a5ac0a56 100644 --- a/plugins/MobileMessaging/SMSProvider/Mediaburst.php +++ b/plugins/MobileMessaging/SMSProvider/Clockwork.php @@ -4,7 +4,7 @@ * * @link http://piwik.org * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later - * @version $Id$$ + * @version $Id$ * * @category Piwik_Plugins * @package Piwik_MobileMessaging_SMSProvider @@ -15,7 +15,7 @@ require_once PIWIK_INCLUDE_PATH . "/plugins/MobileMessaging/APIException.php"; * * @package Piwik_MobileMessaging_SMSProvider */ -class Piwik_MobileMessaging_SMSProvider_Mediaburst extends Piwik_MobileMessaging_SMSProvider +class Piwik_MobileMessaging_SMSProvider_Clockwork extends Piwik_MobileMessaging_SMSProvider { const SOCKET_TIMEOUT = 15; @@ -26,42 +26,40 @@ class Piwik_MobileMessaging_SMSProvider_Mediaburst extends Piwik_MobileMessaging const ERROR_STRING = 'Error'; const MAXIMUM_FROM_LENGTH = 11; - const MAXIMUM_CONTENT_LENGTH = 459; + const MAXIMUM_CONCATENATED_SMS = 3; - public function verifyCredential($username, $password) + public function verifyCredential($apiKey) { - $this->getCreditLeft($username, $password); + $this->getCreditLeft($apiKey); return true; } - public function sendSMS($username, $password, $smsText, $phoneNumber, $from) + public function sendSMS($apiKey, $smsText, $phoneNumber, $from) { $from = substr($from, 0, self::MAXIMUM_FROM_LENGTH); - //@review the length of the SMS text is limited by Mediaburst. Here, we truncate the SMS content because MultiSites.getAll can return a lot of sites. Is this the proper way to handle this case? - $smsText = substr($smsText, 0, self::MAXIMUM_CONTENT_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( - $username, - $password, + $apiKey, self::SEND_SMS_RESOURCE, $additionalParameters ); } - private function issueApiCall($username, $password, $resource, $additionalParameters = array()) + private function issueApiCall($apiKey, $resource, $additionalParameters = array()) { $accountParameters = array( - 'Username' => $username, - 'Password' => $password, + 'Key' => $apiKey, ); $parameters = array_merge($accountParameters, $additionalParameters); @@ -87,18 +85,17 @@ class Piwik_MobileMessaging_SMSProvider_Mediaburst extends Piwik_MobileMessaging if(strpos($result, self::ERROR_STRING) !== false) { throw new Piwik_MobileMessaging_APIException( - 'Mediaburst API returned the following error message : ' . $result + 'Clockwork API returned the following error message : ' . $result ); } return $result; } - public function getCreditLeft($username, $password) + public function getCreditLeft($apiKey) { return $this->issueApiCall( - $username, - $password, + $apiKey, self::CHECK_CREDIT_RESOURCE ); } diff --git a/plugins/MobileMessaging/lang/en.php b/plugins/MobileMessaging/lang/en.php index 5f14e7760f..d5ad9543fc 100644 --- a/plugins/MobileMessaging/lang/en.php +++ b/plugins/MobileMessaging/lang/en.php @@ -15,24 +15,38 @@ $translations = array( 'MobileMessaging_PluginDescription' => 'Create and download custom SMS reports and have them sent to your mobile daily, weekly or monthly.', 'MobileMessaging_TopMenu' => 'Email & SMS Reports', 'MobileMessaging_SettingsMenu' => 'Mobile Messaging', - 'MobileMessaging_VerificationText' => 'Code is %s. To validate your phone number and receive Piwik SMS reports please copy this code in the form accessible via Piwik > Settings > SMS.', + 'MobileMessaging_Settings_SuperAdmin' => 'Super Admin Settings', + 'MobileMessaging_VerificationText' => 'Code is %s. To validate your phone number and receive Piwik SMS reports please copy this code in the form accessible via Piwik > %s > %s.', 'MobileMessaging_Settings_LetUsersManageAPICredential' => 'Allow users to manage their own SMS API credential', + 'MobileMessaging_Settings_LetUsersManageAPICredential_No_Help' => 'All users are able to receive SMS Reports and will use your account\'s credits.', 'MobileMessaging_Settings_SMSProvider' => 'SMS Provider', - 'MobileMessaging_Settings_SMSAPIAccount' => 'SMS API Account', + 'MobileMessaging_Settings_SMSAPIAccount' => 'Manage SMS API Account', 'MobileMessaging_Settings_PhoneNumbers' => 'Phone Numbers', - 'MobileMessaging_Settings_UpdateAccount' => 'Update Account', - 'MobileMessaging_Settings_DeleteAccount' => 'Delete Account', - 'MobileMessaging_Settings_Username' => 'Username', - 'MobileMessaging_Settings_Password' => 'Password', + 'MobileMessaging_Settings_PhoneNumbers_Help' => 'Before receiving SMS (text messages) reports on a phone, the phone number must be entered below. <br/> When you click "Add", a SMS containing a code will be sent to the phone. The user will then be able to validate the phone number if he has access to Piwik.', + 'MobileMessaging_Settings_PhoneNumbers_CountryCode_Help' => 'If you do not know the phone country code, look for your country here', + 'MobileMessaging_Settings_PhoneNumbers_Add' => 'Add a new Phone Number', + 'MobileMessaging_Settings_VerificationCodeJustSent' => 'We just sent a SMS to this number with a code: please enter this code above and click "Validate".', + 'MobileMessaging_Settings_PhoneActivated' => 'Phone number validated! You can now receive SMS with your stats.', + 'MobileMessaging_Settings_InvalidActivationCode' => 'Code entered was not valid, please try again.', + 'MobileMessaging_Settings_CountryCode' => 'Country Code', + 'MobileMessaging_Settings_PhoneNumber' => 'Phone Number', + 'MobileMessaging_Settings_ManagePhoneNumbers' => 'Manage Phone Numbers', + 'MobileMessaging_Settings_PleaseSignUp' => 'To create SMS reports and receive short text messages with your websites\' stats on your mobile phone, please sign up with the SMS API and enter your information below.', + 'MobileMessaging_Settings_APIKey' => 'API Key', 'MobileMessaging_Settings_AddPhoneNumber' => 'Add', 'MobileMessaging_Settings_ValidatePhoneNumber' => 'Validate', 'MobileMessaging_Settings_RemovePhoneNumber' => 'Remove', 'MobileMessaging_Settings_SuspiciousPhoneNumber' => 'If you don\'t receive the text message, you may try without the leading zero. ie. "53948298"', - 'MobileMessaging_Settings_CredentialNotProvidedByAdmin' => 'You can not configure phone numbers. The SMS API account has not been correctly configured. Please contact your administrator.', - 'MobileMessaging_Settings_CredentialNotProvided' => 'You can not configure phone numbers. The API username and password have not been correctly configured.', - 'MobileMessaging_Settings_CredentialProvided' => 'The %s SMS API account associated with username %s is correctly configured.', + 'MobileMessaging_Settings_CredentialNotProvidedByAdmin' => 'Before you can create and manage phone numbers, please ask your administrator to connect Piwik to a SMS Account.', + 'MobileMessaging_Settings_CredentialNotProvided' => 'Before you can create and manage phone numbers, please connect Piwik to your SMS Account above.', + 'MobileMessaging_Settings_CredentialProvided' => 'Your %s SMS API account is correctly configured!', + 'MobileMessaging_Settings_UpdateOrDeleteAccount' => 'You can also %supdate%s or %sdelete%s this account.', + 'MobileMessaging_Settings_DeleteAccountConfirm' => 'Are you sure you want to delete the SMS account?', 'MobileMessaging_MobileReport_PhoneNumbers' => 'Phone Numbers', 'MobileMessaging_MobileReport_NoPhoneNumbers' => 'Please activate at least one phone number by accessing', 'MobileMessaging_MobileReport_MobileMessagingSettingsLink' => 'the Mobile Messaging settings page', 'MobileMessaging_MobileReport_AdditionalPhoneNumbers' => 'You can add more phone numbers by accessing', + 'MobileMessaging_SMS_Content_Too_Long' => '[too long]', + 'MobileMessaging_MultiSites_Must_Be_Activated' => 'To generate SMS texts of your website stats, please enable the plugin MultiSites in Piwik.', + 'MobileMessaging_SMSProvider_Description_Clockwork' => 'You can use Clockwork.com to send SMS Reports from Piwik.<br/> * First, get an API Key form <a href="http://clockworksms.com/platforms/piwik/">Clockwork</a> (Signup is free with some test messages) <br/> * Put your Clockwork API Key in Piwik. <br/> About Clockwork <br/> * Clockwork gives you fast, reliable high quality worldwide SMS delivery, over 450 networks in every corner of the globe. <br/> * Cost per SMS message is circa ~0.08USD (0.06EUR). </br> * Most countries and networks are supported but we suggest you check the latest position on their coverage map here <a href="www.clockworksms.com/sms-coverage/">www.clockworksms.com/sms-coverage/</a>', ); diff --git a/plugins/MobileMessaging/scripts/MobileMessagingSettings.js b/plugins/MobileMessaging/scripts/MobileMessagingSettings.js index d4fc7f639f..55c5a24966 100644 --- a/plugins/MobileMessaging/scripts/MobileMessagingSettings.js +++ b/plugins/MobileMessaging/scripts/MobileMessagingSettings.js @@ -16,19 +16,26 @@ var MobileMessagingSettings = MobileMessagingSettings || (function () { apiAccountSubmitSelector = '#apiAccountSubmit', addPhoneNumberSubmitSelector = '#addPhoneNumberSubmit', providersSelector = '#smsProviders', - usernameSelector = '#username', - passwordSelector = '#password', + providerDescriptionsSelector = '.providerDescription', + apiKeySelector = '#apiKey', countriesSelector = '#countries', - countryCallingCodeAttribute = 'calling-code', 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', + autoCompleteInputSelector = 'input.ui-autocomplete-input', + phoneNumberActivatedSelector = '#phoneNumberActivated', + invalidActivationCodeMsgSelector = '#invalidActivationCode', ajaxErrorsSelector = 'ajaxErrorMobileMessagingSettings', + invalidVerificationCodeAjaxErrorSelector = 'invalidVerificationCodeAjaxError', ajaxLoadingSelector = 'ajaxLoadingMobileMessagingSettings'; /************************************************************ @@ -39,30 +46,70 @@ var MobileMessagingSettings = MobileMessagingSettings || (function () { $(delegatedManagementSelector).change(updateDelegatedManagement); $(apiAccountSubmitSelector).click(updateApiAccount); - $(deleteAcountSelector).click(deleteApiAccount); + $(deleteAcountSelector).click(confirmDeleteApiAccount); + $(displayAccountFormSelector).click(displayAccountForm); $(addPhoneNumberSubmitSelector).click(addPhoneNumber); $(newPhoneNumberSelector).keyup(updateSuspiciousPhoneNumberMessage); $(validatePhoneNumberSubmitSelector).click(validatePhoneNumber); $(removePhoneNumberSubmitSelector).click(removePhoneNumber); - - var defaultCountry = getSelectedCountry(); - $(countriesSelector).selectToAutocomplete(); - // previous function seems to reset the pre-selected option - defaultCountry.attr('selected', 'selected'); - + $(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 verificationCode = phoneNumberContainer.find(verificationCodeSelector).val(); + var verificationCodeContainer = phoneNumberContainer.find(verificationCodeSelector); + var verificationCode = verificationCodeContainer.val(); var phoneNumber = phoneNumberContainer.find(phoneNumberSelector).html(); if(verificationCode != null && verificationCode != '') { - var ajaxRequest = piwikHelper.getStandardAjaxConf(ajaxLoadingSelector, ajaxErrorsSelector); + var ajaxRequest = piwikHelper.getStandardAjaxConf(ajaxLoadingSelector, invalidVerificationCodeAjaxErrorSelector); + + ajaxRequest.success = + function(response) + { + piwikHelper.hideAjaxLoading(ajaxLoadingSelector); + $(phoneNumberActivatedSelector).hide(); + if(!response.value) + { + piwikHelper.showAjaxError($(invalidActivationCodeMsgSelector).html(), invalidVerificationCodeAjaxErrorSelector); + } + else + { + piwikHelper.hideAjaxError(invalidVerificationCodeAjaxErrorSelector); + $(phoneNumberActivatedSelector).show(); + $(verificationCodeContainer).remove(); + $(phoneNumberContainer).find(validatePhoneNumberSubmitSelector).remove(); + $(phoneNumberContainer).find(formDescriptionSelector).remove(); + } + }; var parameters = {}; ajaxRequest.data = parameters; @@ -119,7 +166,7 @@ var MobileMessagingSettings = MobileMessagingSettings || (function () { var phoneNumber = '+' + countryCallingCode + newPhoneNumber; - if(phoneNumber != null && phoneNumber != '') + if(newPhoneNumber != null && newPhoneNumber != '') { var ajaxRequest = piwikHelper.getStandardAjaxConf(ajaxLoadingSelector, ajaxErrorsSelector); @@ -136,21 +183,25 @@ var MobileMessagingSettings = MobileMessagingSettings || (function () { } } - function getSelectedCountry() + function updateCountryCallingCode() { - return $(countriesSelector + ' option:selected'); + $(countryCallingCodeSelector).val($(countriesSelector + ' option:selected').val()); } - function updateCountryCallingCode() + function updateProviderDescription() { - $(countryCallingCodeSelector).val( - getSelectedCountry().attr(countryCallingCodeAttribute) - ); + $(providerDescriptionsSelector).hide(); + $('#' + $(providersSelector + ' option:selected').val() + providerDescriptionsSelector).show(); } function updateDelegatedManagement() { setDelegatedManagement(getDelegatedManagement()); } + + function confirmDeleteApiAccount() + { + piwikHelper.modalConfirm(confirmDeleteAccountSelector, {yes: deleteApiAccount}); + } function deleteApiAccount() { @@ -170,10 +221,9 @@ var MobileMessagingSettings = MobileMessagingSettings || (function () { function updateApiAccount() { var provider = $(providersSelector + ' option:selected').val(); - var username = $(usernameSelector).val(); - var password = $(passwordSelector).val(); + var apiKey = $(apiKeySelector).val(); - if(username != '' && password != '') { + if(apiKey != '') { var ajaxRequest = piwikHelper.getStandardAjaxConf(ajaxLoadingSelector, ajaxErrorsSelector); @@ -182,10 +232,9 @@ var MobileMessagingSettings = MobileMessagingSettings || (function () { parameters.module = 'API'; parameters.format = 'json'; - parameters.method = 'MobileMessaging.setSMSAPICredential'; - parameters.provider = provider; - parameters.username = username; - parameters.password = password; + parameters.method = 'MobileMessaging.setSMSAPICredential'; + parameters.provider = provider; + parameters.apiKey = apiKey; parameters.token_auth = piwik.token_auth; $.ajax(ajaxRequest); diff --git a/plugins/MobileMessaging/scripts/jquery.select-to-autocomplete.js b/plugins/MobileMessaging/scripts/jquery.select-to-autocomplete.js deleted file mode 100644 index 600e88eb87..0000000000 --- a/plugins/MobileMessaging/scripts/jquery.select-to-autocomplete.js +++ /dev/null @@ -1,283 +0,0 @@ -/* -Version: 1.0.5 - -Documentation: http://baymard.com/labs/country-selector#documentation - -Copyright (C) 2011 by Jamie Appleseed, Baymard Institute (baymard.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -(function($){ - var settings = { - 'sort': false, - 'sort-attr': 'data-priority', - 'sort-desc': false, - 'autoselect': true, - 'alternative-spellings': true, - 'alternative-spellings-attr': 'data-alternative-spellings', - 'remove-valueless-options': true, - 'copy-attributes-to-text-field': true, - 'autocomplete-plugin': 'jquery_ui', - 'relevancy-sorting': true, - 'relevancy-sorting-partial-match-value': 1, - 'relevancy-sorting-strict-match-value': 5, - 'relevancy-sorting-booster-attr': 'data-relevancy-booster', - handle_invalid_input: function( context ) { - context.$text_field.val( context.$select_field.find('option:selected:first').text() ); - }, - handle_select_field: function( $select_field ) { - return $select_field.hide(); - }, - insert_text_field: function( context ) { - var $text_field = $( "<input></input>" ); - if ( settings['copy-attributes-to-text-field'] ) { - var attrs = {}; - var raw_attrs = context.$select_field[0].attributes; - for (var i=0; i < raw_attrs.length; i++) { - var key = raw_attrs[i].nodeName; - var value = raw_attrs[i].nodeValue; - if ( key !== 'name' && key !== 'id' ) { - attrs[key] = raw_attrs[i].nodeValue; - } - }; - $text_field.attr( attrs ); - } - $text_field.blur(function() { - var valid_values = context.$select_field.find('option').map(function(i, option) { return $(option).text(); }); - if ( !($text_field.val() in valid_values) && typeof settings['handle_invalid_input'] === 'function' ) { - settings['handle_invalid_input'](context); - } - }); - // give the input box the ability to select all text on mouse click - if ( context.settings['autoselect'] ) { - $text_field.click( function() { - this.select(); - }); - } - return $text_field.val( context.$select_field.find('option:selected:first').text() ) - .insertAfter( context.$select_field ); - }, - extract_options: function( $select_field ) { - var options = []; - var $options = $select_field.find('option'); - var number_of_options = $options.length; - - // go over each option in the select tag - $options.each(function(){ - var $option = $(this); - var option = { - 'real-value': $option.attr('value'), - 'label': $option.text() - } - if ( settings['remove-valueless-options'] && option['real-value'] === '') { - // skip options without a value - } else { - // prepare the 'matches' string which must be filtered on later - option['matches'] = option['label']; - var alternative_spellings = $option.attr( settings['alternative-spellings-attr'] ); - if ( alternative_spellings ) { - option['matches'] += ' ' + alternative_spellings; - } - // give each option a weight paramter for sorting - if ( settings['sort'] ) { - var weight = parseInt( $option.attr( settings['sort-attr'] ), 10 ); - if ( weight ) { - option['weight'] = weight; - } else { - option['weight'] = number_of_options; - } - } - // add relevancy score - if ( settings['relevancy-sorting'] ) { - option['relevancy-score'] = 0; - option['relevancy-score-booster'] = 1; - var boost_by = parseFloat( $option.attr( settings['relevancy-sorting-booster-attr'] ) ); - if ( boost_by ) { - option['relevancy-score-booster'] = boost_by; - } - } - // add option to combined array - options.push( option ); - } - }); - // sort the options based on weight - if ( settings['sort'] ) { - if ( settings['sort-desc'] ) { - options.sort( function( a, b ) { return b['weight'] - a['weight']; } ); - } else { - options.sort( function( a, b ) { return a['weight'] - b['weight']; } ); - } - } - - // return the set of options, each with the following attributes: real-value, label, matches, weight (optional) - return options; - } - }; - - var public_methods = { - init: function( customizations ) { - - if ( $.browser.msie && parseInt($.browser.version, 10) <= 7) { - - return this; - - } else { - - settings = $.extend( settings, customizations ); - - return this.each(function(){ - var $select_field = $(this); - - var context = { - '$select_field': $select_field, - 'options': settings['extract_options']( $select_field ), - 'settings': settings - }; - - context['$text_field'] = settings['insert_text_field']( context ); - - settings['handle_select_field']( $select_field ); - - if ( typeof settings['autocomplete-plugin'] === 'string' ) { - adapters[settings['autocomplete-plugin']]( context ); - } else { - settings['autocomplete-plugin']( context ); - } - }); - - } - - } - }; - - var adapters = { - jquery_ui: function( context ) { - // loose matching of search terms - var filter_options = function( term ) { - var split_term = term.split(' '); - var matchers = []; - for (var i=0; i < split_term.length; i++) { - if ( split_term[i].length > 0 ) { - var matcher = {}; - matcher['partial'] = new RegExp( $.ui.autocomplete.escapeRegex( split_term[i] ), "i" ); - if ( context.settings['relevancy-sorting'] ) { - matcher['strict'] = new RegExp( "^" + $.ui.autocomplete.escapeRegex( split_term[i] ), "i" ); - } - matchers.push( matcher ); - } - }; - - return $.grep( context.options, function( option ) { - var partial_matches = 0; - if ( context.settings['relevancy-sorting'] ) { - var strict_match = false; - var split_option_matches = option.matches.split(' '); - } - for ( var i=0; i < matchers.length; i++ ) { - if ( matchers[i]['partial'].test( option.matches ) ) { - partial_matches++; - } - if ( context.settings['relevancy-sorting'] ) { - for (var q=0; q < split_option_matches.length; q++) { - if ( matchers[i]['strict'].test( split_option_matches[q] ) ) { - strict_match = true; - break; - } - }; - } - }; - if ( context.settings['relevancy-sorting'] ) { - var option_score = 0; - option_score += partial_matches * context.settings['relevancy-sorting-partial-match-value']; - if ( strict_match ) { - option_score += context.settings['relevancy-sorting-strict-match-value']; - } - option_score = option_score * option['relevancy-score-booster']; - option['relevancy-score'] = option_score; - } - return (!term || matchers.length === partial_matches ); - }); - } - // update the select field value using either selected option or current input in the text field - var update_select_value = function( option ) { - if ( option ) { - if ( context.$select_field.val() !== option['real-value'] ) { - context.$select_field.val( option['real-value'] ); - context.$select_field.change(); - } - } else { - var option_name = context.$text_field.val().toLowerCase(); - var matching_option = { 'real-value': false }; - for (var i=0; i < context.options.length; i++) { - if ( option_name === context.options[i]['label'].toLowerCase() ) { - matching_option = context.options[i]; - break; - } - }; - if ( context.$select_field.val() !== matching_option['real-value'] ) { - context.$select_field.val( matching_option['real-value'] || '' ); - context.$select_field.change(); - } - if ( matching_option['real-value'] ) { - context.$text_field.val( matching_option['label'] ); - } - if ( typeof context.settings['handle_invalid_input'] === 'function' && context.$select_field.val() === '' ) { - context.settings['handle_invalid_input']( context ); - } - } - } - // jQuery UI autocomplete settings & behavior - context.$text_field.autocomplete({ - 'minLength': 0, - 'delay': 0, - 'autoFocus': true, - source: function( request, response ) { - var filtered_options = filter_options( request.term ); - if ( context.settings['relevancy-sorting'] ) { - filtered_options = filtered_options.sort( function( a, b ) { return b['relevancy-score'] - a['relevancy-score']; } ); - } - response( filtered_options ); - }, - select: function( event, ui ) { - update_select_value( ui.item ); - }, - change: function( event, ui ) { - update_select_value( ui.item ); - } - }); - // force refresh value of select field when form is submitted - context.$text_field.parents('form:first').submit(function(){ - update_select_value(); - }); - // select current value - update_select_value(); - } - }; - - $.fn.selectToAutocomplete = function( method ) { - if ( public_methods[method] ) { - return public_methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 )); - } else if ( typeof method === 'object' || ! method ) { - return public_methods.init.apply( this, arguments ); - } else { - $.error( 'Method ' + method + ' does not exist on jQuery.fn.selectToAutocomplete' ); - } - }; - -})(jQuery); diff --git a/plugins/MobileMessaging/templates/ReportParameters.tpl b/plugins/MobileMessaging/templates/ReportParameters.tpl index 7a6af178f0..cc2ffb1de5 100644 --- a/plugins/MobileMessaging/templates/ReportParameters.tpl +++ b/plugins/MobileMessaging/templates/ReportParameters.tpl @@ -56,6 +56,6 @@ {/foreach} {'MobileMessaging_MobileReport_AdditionalPhoneNumbers'|translate} {/if} - <a href='{url module="MobileMessaging"}'>{'MobileMessaging_MobileReport_MobileMessagingSettingsLink'|translate}</a> + <a href='{url module="MobileMessaging" updated="false"}'>{'MobileMessaging_MobileReport_MobileMessagingSettingsLink'|translate}</a> </td> </tr> diff --git a/plugins/MobileMessaging/templates/SMSReport.tpl b/plugins/MobileMessaging/templates/SMSReport.tpl index eb007bbe51..80caba02c0 100644 --- a/plugins/MobileMessaging/templates/SMSReport.tpl +++ b/plugins/MobileMessaging/templates/SMSReport.tpl @@ -1,5 +1,10 @@ {strip} {$prettyDate}.{literal} {/literal} + + {if empty($reportRows)} + {'CoreHome_ThereIsNoDataForThisReport'|translate} + {/if} + {foreach name=reportRows from=$reportRows item=row key=rowId} {assign var=rowMetrics value=$row->getColumns()} diff --git a/plugins/MobileMessaging/templates/Settings.tpl b/plugins/MobileMessaging/templates/Settings.tpl index 3b97e3981c..6cbdcd4ea5 100644 --- a/plugins/MobileMessaging/templates/Settings.tpl +++ b/plugins/MobileMessaging/templates/Settings.tpl @@ -3,54 +3,44 @@ {include file='CoreAdminHome/templates/header.tpl'} {loadJavascriptTranslations plugins='MobileMessaging'} -{* TODO this UI probably needs some embellishment by working out a better HTML structure (table ? list ?), specifying better locations for errors and so on *} - -{if $isSuperUser} -<h2>{'MobileMessaging_Settings_LetUsersManageAPICredential'|translate}</h2> - -<input - type='radio' - value='true' - name='delegatedManagement'{if $delegatedManagement} checked='checked'{/if} /> -{'General_Yes'|translate} - -<input - type='radio' - value='false' - name='delegatedManagement'{if !$delegatedManagement} checked='checked'{/if} /> -{'General_No'|translate} - -{/if} - {if $accountManagedByCurrentUser} <h2>{'MobileMessaging_Settings_SMSAPIAccount'|translate}</h2> {if $credentialSupplied} - {'MobileMessaging_Settings_CredentialProvided'|translate:$provider:$APIUsername} + {'MobileMessaging_Settings_CredentialProvided'|translate:$provider} {$creditLeft} - <a id='deleteAccount'>{'MobileMessaging_Settings_DeleteAccount'|translate}</a> <br/> + {'MobileMessaging_Settings_UpdateOrDeleteAccount'|translate:"<a id='displayAccountForm'>":"</a>":"<a id='deleteAccount'>":"</a>"} + {else} + {'MobileMessaging_Settings_PleaseSignUp'|translate} {/if} - {'MobileMessaging_Settings_UpdateAccount'|translate} : <br/> + <div id='accountForm' {if $credentialSupplied}style='display: none;'{/if}> + <br/> + {'MobileMessaging_Settings_SMSProvider'|translate} + <select id='smsProviders'> + {foreach from=$smsProviders key=smsProvider item=description} + <option value='{$smsProvider}'> + {$smsProvider} + </option> + {/foreach} + </select> - {'MobileMessaging_Settings_SMSProvider'|translate} - <select id="smsProviders"> - {foreach from=$smsProviders item=smsProvider} - <option value="{$smsProvider}"> - {$smsProvider} - </option> - {/foreach} - </select> + {'MobileMessaging_Settings_APIKey'|translate} + <input size='25' id='apiKey'/> - {'MobileMessaging_Settings_Username'|translate} - <input size='25' id='username'/> + <input type='submit' value='{'General_Save'|translate}' id='apiAccountSubmit' class='submit' /> - {'MobileMessaging_Settings_Password'|translate} - <input size='25' id='password' type='password' autocomplete='off'/> + {foreach from=$smsProviders key=smsProvider item=description} + <p class='providerDescription' id='{$smsProvider}'> + {$description|translate} + </p> + {/foreach} - <input type='submit' value='{'General_Save'|translate}' id='apiAccountSubmit' class='submit' /> + </div> {/if} +{ajaxErrorDiv id=ajaxErrorMobileMessagingSettings} + <h2>{'MobileMessaging_Settings_PhoneNumbers'|translate}</h2> {if !$credentialSupplied} {if $accountManagedByCurrentUser} @@ -59,30 +49,53 @@ {'MobileMessaging_Settings_CredentialNotProvidedByAdmin'|translate} {/if} {else} + + {'MobileMessaging_Settings_PhoneNumbers_Help'|translate}<br/><br/> + <strong>{'MobileMessaging_Settings_PhoneNumbers_Add'|translate}</strong><br/><br/> + <span id='suspiciousPhoneNumber' style='display:none;'> - {'MobileMessaging_Settings_SuspiciousPhoneNumber'|translate} - <br/> + {'MobileMessaging_Settings_SuspiciousPhoneNumber'|translate}<br/><br/> </span> + + +<input id='countryCallingCode' size='7' maxlength='4'/> + <input id='newPhoneNumber'/> + <input + type='submit' + value='{'MobileMessaging_Settings_AddPhoneNumber'|translate}' + id='addPhoneNumberSubmit' + /> + + <br/> + <span class="form-description">{'MobileMessaging_Settings_CountryCode'|translate}</span><span class="form-description">{'MobileMessaging_Settings_PhoneNumber'|translate}</span><br/><br/> + + {'MobileMessaging_Settings_PhoneNumbers_CountryCode_Help'|translate} <select id='countries'> - <option> </option> {* this is a trick to avoid selecting the first country when no default could be found *} + <option value=''> </option> {* this is a trick to avoid selecting the first country when no default could be found *} {foreach from=$countries key=countryCode item=country} <option - value='{$countryCode}' - calling-code='{$country.countryCallingCode}' + value='{$country.countryCallingCode}' {if $defaultCountry==$countryCode} selected='selected' {/if} - > - {$country.countryName} - </option> + > + {$country.countryName} + </option> {/foreach} </select> - +<input id='countryCallingCode'/> - <input id='newPhoneNumber'/> - <input - type='submit' - value='{'MobileMessaging_Settings_AddPhoneNumber'|translate}' - id='addPhoneNumberSubmit' - class='submit' - /> + + {if $phoneNumbers|@count gt 0} + <br/> + <br/> + <strong>{'MobileMessaging_Settings_ManagePhoneNumbers'|translate}</strong><br/><br/> + {/if} + + {ajaxErrorDiv id=invalidVerificationCodeAjaxError} + + <div id='phoneNumberActivated' class="ajaxSuccess" style="display:none;"> + {'MobileMessaging_Settings_PhoneActivated'|translate} + </div> + + <div id='invalidActivationCode' style="display:none;"> + {'MobileMessaging_Settings_InvalidActivationCode'|translate} + </div> <ul> {foreach from=$phoneNumbers key=phoneNumber item=validated} @@ -93,20 +106,64 @@ <input type='submit' value='{'MobileMessaging_Settings_ValidatePhoneNumber'|translate}' - class='submit validatePhoneNumberSubmit' + class='validatePhoneNumberSubmit' /> {/if} <input type='submit' value='{'MobileMessaging_Settings_RemovePhoneNumber'|translate}' - class='submit removePhoneNumberSubmit' + class='removePhoneNumberSubmit' /> + {if !$validated} + <br/> + <span class='form-description'>{'MobileMessaging_Settings_VerificationCodeJustSent'|translate}</span> + {/if} + <br/> + <br/> </li> {/foreach} </ul> {/if} -{ajaxErrorDiv id=ajaxErrorMobileMessagingSettings} +{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='true' + name='delegatedManagement' {if $delegatedManagement} checked='checked'{/if} /> + {'General_Yes'|translate} + <br/> + </label> + <br/> + + <label> + <input + type='radio' + value='false' + name='delegatedManagement' {if !$delegatedManagement} checked='checked'{/if} /> + {'General_No'|translate} + <br/> + <span class='form-description'>({'General_Default'|translate}) {'MobileMessaging_Settings_LetUsersManageAPICredential_No_Help'|translate}</span> + </label> + </fieldset> + </tr> + </table> +{/if} + {ajaxLoadingDiv id=ajaxLoadingMobileMessagingSettings} {include file='CoreAdminHome/templates/footer.tpl'} + +<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> + diff --git a/plugins/MultiSites/API.php b/plugins/MultiSites/API.php index bc87e2902b..435c8891ba 100755 --- a/plugins/MultiSites/API.php +++ b/plugins/MultiSites/API.php @@ -217,7 +217,7 @@ class Piwik_MultiSites_API } // remove eCommerce related metrics on non eCommerce Piwik sites - // @review this is not optimal in terms of performance: those metrics should not be retrieved in the first place + // note: this is not optimal in terms of performance: those metrics should not be retrieved in the first place if($enhanced) { // $dataTableRows instanceOf Piwik_DataTable_Row[] @@ -254,13 +254,17 @@ class Piwik_MultiSites_API $dataTable->filter('Sort', array(self::NB_VISITS_METRIC, 'desc', $naturalSort = false)); // filter rows without visits - $dataTable->filter( - 'ColumnCallbackDeleteRow', - array( - self::NB_VISITS_METRIC, - create_function ( '$value', 'return $value != 0;') - ) - ); + // note: if only one website is queried and there are no visits, we can not remove the row otherwise Piwik_API_ResponseBuilder throws 'Call to a member function getColumns() on a non-object' + if($allWebsitesRequested) + { + $dataTable->filter( + 'ColumnCallbackDeleteRow', + array( + self::NB_VISITS_METRIC, + create_function ( '$value', 'return $value != 0;') + ) + ); + } return $dataTable; } diff --git a/plugins/PDFReports/API.php b/plugins/PDFReports/API.php index 9628c516f1..e410885e42 100644 --- a/plugins/PDFReports/API.php +++ b/plugins/PDFReports/API.php @@ -37,6 +37,7 @@ class Piwik_PDFReports_API const OUTPUT_DOWNLOAD = 1; const OUTPUT_SAVE_ON_DISK = 2; + const OUTPUT_INLINE = 3; const REPORT_TYPE_INFO_KEY = 'reportType'; const ID_SITE_INFO_KEY = 'idSite'; @@ -281,7 +282,7 @@ class Piwik_PDFReports_API * @param int $idReport ID of the report to generate. * @param string $date YYYY-MM-DD * @param bool|false|string $language If not passed, will use default language. - * @param bool|false|int $outputType 1 = download report, 2 = save report to disk, defaults to download + * @param bool|false|int $outputType 1 = download report, 2 = save report to disk, 3 = output report in browser, defaults to download * @param bool|false|string $period Defaults to 'day'. If not specified, will default to the report's period set when creating the report * @param bool|false|string $reportFormat 'pdf', 'html' or any other format provided via the PDFReports.getReportFormats hook * @param bool|false|string $parameters JSON encoded parameters @@ -434,7 +435,7 @@ class Piwik_PDFReports_API // init report renderer $reportRenderer->setLocale($language); - $reportRenderer->setRenderImageInline($outputType == self::OUTPUT_DOWNLOAD ? true : false); + $reportRenderer->setRenderImageInline($outputType != self::OUTPUT_SAVE_ON_DISK); // render report $websiteName = Piwik_Site::getNameFor($idSite); @@ -480,6 +481,11 @@ class Piwik_PDFReports_API ); break; + case self::OUTPUT_INLINE: + + $reportRenderer->sendToBrowserInline("$websiteName - $prettyDate - $description"); + break; + default: case self::OUTPUT_DOWNLOAD: $reportRenderer->sendToBrowserDownload("$websiteName - $prettyDate - $description"); @@ -604,7 +610,7 @@ class Piwik_PDFReports_API { if(!self::allowMultipleReports($reportType)) { - //@review sms can only contain one report, we currently silently discard all reports except the first one, is this ok or should we raise an exception? + //sms can only contain one report, we silently discard all but the first $requestedReports = array_slice($requestedReports, 0, 1); } diff --git a/plugins/PDFReports/Controller.php b/plugins/PDFReports/Controller.php index 36e4f80cf4..2814fa5101 100644 --- a/plugins/PDFReports/Controller.php +++ b/plugins/PDFReports/Controller.php @@ -67,7 +67,7 @@ class Piwik_PDFReports_Controller extends Piwik_Controller $view->reports = $reports; $view->reportsJSON = Piwik_Common::json_encode($reportsById); - $view->downloadOutputType = Piwik_PDFReports_API::OUTPUT_DOWNLOAD; + $view->downloadOutputType = Piwik_PDFReports_API::OUTPUT_INLINE; $periods = array_merge( array('never' => Piwik_Translate('General_Never')), diff --git a/plugins/PDFReports/templates/add.tpl b/plugins/PDFReports/templates/add.tpl index d2492aa9eb..ffb1d29dce 100644 --- a/plugins/PDFReports/templates/add.tpl +++ b/plugins/PDFReports/templates/add.tpl @@ -105,8 +105,8 @@ <div class='reportCategory'>{$category}</div><ul class='listReports'> {foreach from=$reports item=report} <li> - <input type='{$reportInputType}' id="{$report.uniqueId}" name='{$reportType}Reports'/> - <label for="{$report.uniqueId}"> + <input type='{$reportInputType}' id="{$reportType}{$report.uniqueId}" report-unique-id='{$report.uniqueId}' name='{$reportType}Reports'/> + <label for="{$reportType}{$report.uniqueId}"> {$report.name|escape:"html"} {if $report.uniqueId=='MultiSites_getAll'} <div class="entityInlineHelp">{'PDFReports_ReportIncludeNWebsites'|translate:"$countWebsites "}</div> diff --git a/plugins/PDFReports/templates/pdf.js b/plugins/PDFReports/templates/pdf.js index e4c5160a89..0172720e00 100644 --- a/plugins/PDFReports/templates/pdf.js +++ b/plugins/PDFReports/templates/pdf.js @@ -41,7 +41,7 @@ function formSetEditReport(idReport) var key; for(key in report.reports) { - $('.' + report.type + ' #' + report.reports[key]).prop('checked','checked'); + $('.' + report.type + ' [report-unique-id=' + report.reports[key] + ']').prop('checked','checked'); } updateReportParametersFunctions[report.type](report.parameters); @@ -88,7 +88,7 @@ function initManagePdf() var reports = []; $('[name=reportsList].'+apiParameters.reportType+' input:checked').each(function() { - reports.push($(this).attr('id')); + reports.push($(this).attr('report-unique-id')); }); if(reports.length > 0) { |