From dc98a971829c9ed278f79e759ba41b51881ba2fc Mon Sep 17 00:00:00 2001 From: benakamoorthi Date: Mon, 26 Nov 2012 22:14:37 +0000 Subject: Fixes #3456, added updating scheduled task for GeoIP databases w/ manager UI and easy-install for GeoLiteCity. Notes: * Added new PEAR lib Archive_Tar and new Unzip implmentations for .tar.gz, .tar.bz2 & .gz files. * Modified Http class to allow use of Range HTTP header. * Added ability to download file in chunks to Http class. * Moved GeoIP admin page styles to separate CSS file. * Allowed monthly scheduled tasks to specify day of week to run on. git-svn-id: http://dev.piwik.org/svn/trunk@7550 59fd770c-687e-43c8-a1e3-f5a4ff64c105 --- plugins/UserCountry/Controller.php | 229 +++++++++++++- plugins/UserCountry/GeoIPAutoUpdater.php | 397 +++++++++++++++++++++++++ plugins/UserCountry/LocationProvider/GeoIp.php | 29 +- plugins/UserCountry/UserCountry.php | 39 ++- plugins/UserCountry/templates/admin.js | 140 ++++++++- plugins/UserCountry/templates/adminIndex.tpl | 42 ++- plugins/UserCountry/templates/styles.css | 69 +++++ plugins/UserCountry/templates/updaterSetup.tpl | 53 ++++ 8 files changed, 980 insertions(+), 18 deletions(-) create mode 100755 plugins/UserCountry/GeoIPAutoUpdater.php create mode 100755 plugins/UserCountry/templates/styles.css create mode 100755 plugins/UserCountry/templates/updaterSetup.tpl (limited to 'plugins/UserCountry') diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php index e7ed5c458a..1df06697c8 100644 --- a/plugins/UserCountry/Controller.php +++ b/plugins/UserCountry/Controller.php @@ -14,7 +14,7 @@ * * @package Piwik_UserCountry */ -class Piwik_UserCountry_Controller extends Piwik_Controller +class Piwik_UserCountry_Controller extends Piwik_Controller_Admin { function index() { @@ -41,6 +41,7 @@ class Piwik_UserCountry_Controller extends Piwik_Controller $view->locationProviders = $allProviderInfo; $view->currentProviderId = Piwik_UserCountry_LocationProvider::getCurrentProviderId(); $view->thisIP = Piwik_IP::getIpFromHeader(); + $view->geoIPDatabasesInstalled = Piwik_UserCountry_LocationProvider_GeoIp::isDatabaseInstalled(); // check if there is a working provider (that isn't the default one) $isThereWorkingProvider = false; @@ -54,6 +55,20 @@ class Piwik_UserCountry_Controller extends Piwik_Controller } } $view->isThereWorkingProvider = $isThereWorkingProvider; + + // if using either the Apache or PECL module, they are working and there are no databases + // in misc, then the databases are located outside of Piwik, so we cannot update them + $view->showGeoIPUpdateSection = true; + $currentProviderId = Piwik_UserCountry_LocationProvider::getCurrentProviderId(); + if (!$view->geoIPDatabasesInstalled + && ($currentProviderId == Piwik_UserCountry_LocationProvider_GeoIp_ServerBased::ID + || $currentProviderId == Piwik_UserCountry_LocationProvider_GeoIp_Pecl::ID) + && $allProviderInfo[$currentProviderId]['status'] == Piwik_UserCountry_LocationProvider::INSTALLED) + { + $view->showGeoIPUpdateSection = false; + } + + $this->setUpdaterManageVars($view); $this->setBasicVariablesView($view); Piwik_Controller_Admin::setBasicVariablesAdminView($view); $view->menu = Piwik_GetAdminMenu(); @@ -61,6 +76,197 @@ class Piwik_UserCountry_Controller extends Piwik_Controller echo $view->render(); } + /** + * Starts or continues download of GeoLiteCity.dat. + * + * To avoid a server/PHP timeout & to show progress of the download to the user, we + * use the HTTP Range header to download one chunk of the file at a time. After each + * chunk, it is the browser's responsibility to call the method again to continue the download. + * + * Input: + * 'continue' query param - if set to 1, will assume we are currently downloading & use + * Range: HTTP header to get another chunk of the file. + * + * Output (in JSON): + * 'current_size' - Current size of the partially downloaded file on disk. + * 'expected_file_size' - The expected finished file size as returned by the HTTP server. + * 'next_screen' - When the download finishes, this is the next screen that should be shown. + * 'error' - When an error occurs, the message is returned in this property. + */ + public function downloadFreeGeoIPDB() + { + Piwik::checkUserIsSuperUser(); + if ($_SERVER["REQUEST_METHOD"] == "POST") + { + $this->checkTokenInUrl(); + + $outputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase('GeoIPCity.dat').'.gz'; + try + { + $result = Piwik_Http::downloadChunk( + $url = Piwik_UserCountry_LocationProvider_GeoIp::GEO_LITE_URL, + $outputPath, + $continue = Piwik_Common::getRequestVar('continue', true, 'int') + ); + + // if the file is done + if ($result['current_size'] >= $result['expected_file_size']) + { + Piwik_UserCountry_GeoIPAutoUpdater::unzipDownloadedFile($outputPath, $unlink = true); + + // setup the auto updater + Piwik_UserCountry_GeoIPAutoUpdater::setUpdaterOptions(array( + 'loc_db' => Piwik_UserCountry_LocationProvider_GeoIp::GEO_LITE_URL, + 'period' => Piwik_UserCountry_GeoIPAutoUpdater::SCHEDULE_PERIOD_MONTHLY, + )); + + // make sure to echo out the geoip updater management screen + $result['next_screen'] = $this->getGeoIpUpdaterManageScreen(); + } + + echo json_encode($result); + } + catch (Exception $ex) + { + echo json_encode(array('error' => $ex->getMessage())); + } + } + } + + /** + * Renders and returns the HTML that manages the GeoIP auto-updater. + * + * @return string + */ + private function getGeoIpUpdaterManageScreen() + { + $view = Piwik_View::factory('updaterSetup'); + $view->geoIPDatabasesInstalled = true; + $this->setUpdaterManageVars($view); + return $view->render(); + } + + /** + * Sets some variables needed by the updaterSetup.tpl template. + * + * @param Piwik_View $view + */ + private function setUpdaterManageVars( $view ) + { + $urls = Piwik_UserCountry_GeoIPAutoUpdater::getConfiguredUrls(); + + $view->geoIPLocUrl = $urls['loc']; + $view->geoIPIspUrl = $urls['isp']; + $view->geoIPOrgUrl = $urls['org']; + $view->geoIPUpdatePeriod = Piwik_UserCountry_GeoIPAutoUpdater::getSchedulePeriod(); + } + + /** + * Sets the URLs used to download new versions of the installed GeoIP databases. + * + * Input (query params): + * 'loc_db' - URL for a GeoIP location database. + * 'isp_db' - URL for a GeoIP ISP database (optional). + * 'org_db' - URL for a GeoIP Org database (optional). + * 'period' - 'weekly' or 'monthly'. Determines how often update is run. + * + * Output (json): + * 'error' - if an error occurs its message is set as the resulting JSON object's + * 'error' property. + */ + public function updateGeoIPLinks() + { + Piwik::checkUserIsSuperUser(); + if ($_SERVER["REQUEST_METHOD"] == "POST") + { + try + { + $this->checkTokenInUrl(); + + Piwik_UserCountry_GeoIPAutoUpdater::setUpdaterOptionsFromUrl(); + + // if there is a updater URL for a database, but its missing from the misc dir, tell + // the browser so it can download it next + $info = $this->getNextMissingDbUrlInfo(); + if ($info !== false) + { + echo json_encode($info); + return; + } + } + catch (Exception $ex) + { + echo json_encode(array('error' => $ex->getMessage())); + } + } + } + + /** + * Starts or continues a download for a missing GeoIP database. A database is missing if + * it has an update URL configured, but the actual database is not available in the misc + * directory. + * + * Input: + * 'url' - The URL to download the database from. + * 'continue' - 1 if we're continuing a download, 0 if we're starting one. + * + * Output: + * 'error' - If an error occurs this describes the error. + * 'to_download' - The URL of a missing database that should be downloaded next (if any). + * 'to_download_label' - The label to use w/ the progress bar that describes what we're + * downloading. + * 'current_size' - Size of the current file on disk. + * 'expected_file_size' - Size of the completely downloaded file. + */ + public function downloadMissingGeoIpDb() + { + Piwik::checkUserIsSuperUser(); + if ($_SERVER["REQUEST_METHOD"] == "POST") + { + try + { + $this->checkTokenInUrl(); + + // based on the database type (provided by the 'key' query param) determine the + // url & output file name + $key = Piwik_Common::getRequestVar('key', null, 'string'); + $url = Piwik_UserCountry_GeoIPAutoUpdater::getConfiguredUrl($key); + + $ext = Piwik_UserCountry_GeoIPAutoUpdater::getGeoIPUrlExtension($url); + $filename = Piwik_UserCountry_LocationProvider_GeoIp::$dbNames[$key][0].'.'.$ext; + + if (substr($filename, 0, 15) == 'GeoLiteCity.dat') + { + $filename = 'GeoIPCity.dat'.substr($filename, 15); + } + $outputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($filename); + + // download part of the file + $result = Piwik_Http::downloadChunk( + $url, $outputPath, Piwik_Common::getRequestVar('continue', true, 'int')); + + // if the file is done + if ($result['current_size'] >= $result['expected_file_size']) + { + Piwik_UserCountry_GeoIPAutoUpdater::unzipDownloadedFile($outputPath, $unlink = true); + + $info = $this->getNextMissingDbUrlInfo(); + if ($info !== false) + { + echo json_encode($info); + return; + } + } + + echo json_encode($result); + } + catch (Exception $ex) + { + echo json_encode(array('error' => $ex->getMessage())); + } + } + } + /** * Sets the current LocationProvider type. * @@ -243,4 +449,25 @@ class Piwik_UserCountry_Controller extends Piwik_Controller $realView->properties = $properties; } } + + /** + * Gets information for the first missing GeoIP database (if any). + * + * @return bool + */ + private function getNextMissingDbUrlInfo() + { + $missingDbs = Piwik_UserCountry_GeoIPAutoUpdater::getMissingDatabases(); + if (!empty($missingDbs)) + { + $missingDbKey = $missingDbs[0]; + $missingDbName = Piwik_UserCountry_LocationProvider_GeoIp::$dbNames[$missingDbKey][0]; + + return array( + 'to_download' => $missingDbKey, + 'to_download_label' => Piwik_Translate('UserCountry_DownloadingDb', $missingDbName).'...', + ); + } + return false; + } } diff --git a/plugins/UserCountry/GeoIPAutoUpdater.php b/plugins/UserCountry/GeoIPAutoUpdater.php new file mode 100755 index 0000000000..391a226937 --- /dev/null +++ b/plugins/UserCountry/GeoIPAutoUpdater.php @@ -0,0 +1,397 @@ + self::LOC_URL_OPTION_NAME, + 'isp' => self::ISP_URL_OPTION_NAME, + 'org' => self::ORG_URL_OPTION_NAME, + ); + + /** + * Attempts to download new location, ISP & organization GeoIP databases and + * replace the existing ones w/ them. + */ + public function update() + { + try + { + $locUrl = Piwik_GetOption(self::LOC_URL_OPTION_NAME); + if ($locUrl !== false) + { + $this->downloadFile('loc', $locUrl); + } + + $ispUrl = Piwik_GetOption(self::ISP_URL_OPTION_NAME); + if ($ispUrl !== false) + { + $this->downloadFile('isp', $ispUrl); + } + + $orgUrl = Piwik_GetOption(self::ORG_URL_OPTION_NAME); + if ($orgUrl !== false) + { + $this->downloadFile('org', $orgUrl); + } + } + catch (Exception $ex) + { + // message will already be prefixed w/ 'Piwik_UserCountry_GeoIPAutoUpdater: ' + Piwik::log($ex->getMessage()); + throw $ex; + } + } + + /** + * Downloads a GeoIP database archive, extracts the .dat file and overwrites the existing + * old database. + * + * If something happens that causes the download to fail, no exception is thrown, but + * an error is logged. + * + * @param string $url URL to the database to download. The type of database is determined + * from this URL. + */ + private function downloadFile( $dbType, $url ) + { + $ext = Piwik_UserCountry_GeoIPAutoUpdater::getGeoIPUrlExtension($url); + $zippedFilename = Piwik_UserCountry_LocationProvider_GeoIp::$dbNames[$dbType][0].'.'.$ext; + + $zippedOutputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($zippedFilename); + + // download zipped file to misc dir + try + { + $success = Piwik_Http::sendHttpRequest($url, $timeout = 3600, $userAgent = null, $zippedOutputPath); + } + catch (Exception $ex) + { + throw new Exception("Piwik_UserCountry_GeoIPAutoUpdater: failed to download '$url' to " + . "'$zippedOutputPath': " . $ex->getMessage()); + } + + if ($success !== true) + { + throw new Exception("Piwik_UserCountry_GeoIPAutoUpdater: failed to download '$url' to " + . "'$zippedOutputPath'! (Unknown error)"); + } + + Piwik::log("Piwik_UserCountry_GeoIPAutoUpdater: successfully downloaded '$url'"); + + try + { + self::unzipDownloadedFile($zippedOutputPath, $unlink = true); + } + catch (Exception $ex) + { + throw new Exception("Piwik_UserCountry_GeoIPAutoUpdater: failed to unzip '$zippedOutputPath' after " + . "downloading " . "'$url': ".$ex->getMessage()); + } + + Piwik::log("Piwik_UserCountry_GeoIPAutoUpdater: successfully updated GeoIP database '$url'"); + } + + /** + * Unzips a downloaded GeoIP database. Only unzips .gz & .tar.gz files. + * + * @param string $path Path to zipped file. + * @param bool $unlink Whether to unlink archive or not. + */ + public static function unzipDownloadedFile( $path, $unlink = false ) + { + $parts = explode('.', basename($path)); + $outputPath = Piwik_UserCountry_LocationProvider_GeoIp::getPathForGeoIpDatabase($parts[0].'.dat'); + + // extract file + if (substr($path, -7, 7) == '.tar.gz') + { + // find the .dat file in the tar archive + $unzip = Piwik_Unzip::factory('tar.gz', $path); + $content = $unzip->listContent(); + + if (empty($content)) + { + throw new Exception(Piwik_Translate('UserCountry_CannotListContent', + array("'$path'", $unzip->errorInfo()))); + } + + $datFile = null; + foreach ($content as $info) + { + $archivedPath = $info['filename']; + if (basename($archivedPath) === basename($outputPath)) + { + $datFile = $archivedPath; + } + } + + if ($datFile === null) + { + throw new Exception(Piwik_Translate('UserCountry_CannotFindGeoIPDatabaseInArchive', + array(basename($outputPath), "'$path'"))); + } + + // extract JUST the .dat file + $unzipped = $unzip->extractInString($datFile); + + if (empty($unzipped)) + { + throw new Exception(Piwik_Translate('UserCountry_CannotUnzipDatFile', + array("'$path'", $unzip->errorInfo()))); + } + + // write unzipped to file + $fd = fopen($outputPath, 'wb'); + fwrite($fd, $unzipped); + fclose($fd); + } + else if (substr($path, -3, 3) == '.gz') + { + $unzip = Piwik_Unzip::factory('gz', $path); + $success = $unzip->extract($outputPath); + + if ($success !== true) + { + throw new Exception(Piwik_Translate('UserCountry_CannotUnzipDatFile', + array("'$path'", $unzip->errorInfo()))); + } + } + else + { + $ext = end(explode(basename($path), '.', 2)); + throw new Exception(Piwik_Translate('UserCountry_UnsupportedArchiveType', "'$ext'")); + } + + // delete original archive + if ($unlink) + { + unlink($path); + } + } + + /** + * Creates a ScheduledTask instance based on set option values. + * + * @return Piwik_ScheduledTask + */ + public static function makeScheduledTask() + { + $instance = new Piwik_UserCountry_GeoIPAutoUpdater(); + + $schedulePeriodStr = self::getSchedulePeriod(); + + // created the scheduledtime instance, also, since GeoIP updates are done on tuesdays, + // get new DBs on Wednesday + switch ($schedulePeriodStr) + { + case self::SCHEDULE_PERIOD_WEEKLY: + $schedulePeriod = new Piwik_ScheduledTime_Weekly(); + $schedulePeriod->setDay(3); + break; + case self::SCHEDULE_PERIOD_MONTHLY: + default: + $schedulePeriod = new Piwik_ScheduledTime_Monthly(); + $schedulePeriod->setDayOfWeek(3, 0); + break; + } + + return new Piwik_ScheduledTask($instance, 'update', $schedulePeriod, Piwik_ScheduledTask::LOWEST_PRIORITY); + } + + /** + * Sets the options used by this class based on query parameter values. + * + * See setUpdaterOptions for query params used. + */ + public static function setUpdaterOptionsFromUrl() + { + self::setUpdaterOptions(array( + 'loc' => Piwik_Common::getRequestVar('loc_db', false, 'string'), + 'isp' => Piwik_Common::getRequestVar('isp_db', false, 'string'), + 'org' => Piwik_Common::getRequestVar('org_db', false, 'string'), + 'period' => Piwik_Common::getRequestVar('period', false, 'string'), + )); + } + + /** + * Sets the options used by this class based on the elements in $options. + * + * The following elements of $options are used: + * 'loc' - URL for location database. + * 'isp' - URL for ISP database. + * 'org' - URL for Organization database. + * 'period' - 'weekly' or 'monthly'. When to run the updates. + * + * @param array $options + */ + public static function setUpdaterOptions( $options ) + { + // set url options + foreach (self::$urlOptions as $optionKey => $optionName) + { + if (empty($options[$optionKey])) + { + continue; + } + + Piwik_SetOption($optionName, $url = $options[$optionKey]); + } + + // set period option + if (!empty($options['period'])) + { + $period = $options['period']; + if ($period != self::SCHEDULE_PERIOD_MONTHLY + && $period != self::SCHEDULE_PERIOD_WEEKLY) + { + throw new Exception(Piwik_Translate( + 'UserCountry_InvalidGeoIPUpdatePeriod', + array("'$period'", "'".self::SCHEDULE_PERIOD_MONTHLY."', '".self::SCHEDULE_PERIOD_WEEKLY."'") + )); + } + + Piwik_SetOption(self::SCHEDULE_PERIOD_OPTION_NAME, $period); + } + } + + /** + * Returns true if the auto-updater is setup to update at least one type of + * database. False if otherwise. + * + * @return bool + */ + public static function isUpdaterSetup() + { + if (Piwik_GetOption(self::LOC_URL_OPTION_NAME) !== false + || Piwik_GetOption(self::ISP_URL_OPTION_NAME) !== false + || Piwik_GetOption(self::ORG_URL_OPTION_NAME) !== false) + { + return true; + } + + return false; + } + + /** + * Retrieves the URLs used to update various GeoIP database files. + * + * @return array + */ + public static function getConfiguredUrls() + { + $result = array(); + foreach (self::$urlOptions as $key => $optionName) + { + $result[$key] = Piwik_GetOption($optionName); + } + return $result; + } + + /** + * Returns the confiured URL (if any) for a type of database. + * + * @param string $key 'loc', 'isp' or 'org' + * @return string|false + */ + public static function getConfiguredUrl( $key ) + { + return Piwik_GetOption(self::$urlOptions[$key]); + } + + /** + * Performs a GeoIP database update. + */ + public static function performUpdate() + { + $instance = new Piwik_UserCountry_GeoIPAutoUpdater(); + $instance->update(); + } + + /** + * Returns the configured update period, either 'week' or 'month'. Defaults to + * 'month'. + * + * @return string + */ + public static function getSchedulePeriod() + { + $period = Piwik_GetOption(self::SCHEDULE_PERIOD_OPTION_NAME); + if ($period === false) + { + $period = self::SCHEDULE_PERIOD_MONTHLY; + } + return $period; + } + + /** + * Returns an array of strings for GeoIP databases that have update URLs configured, but + * are not present in the misc directory. Each string is a key describing the type of + * database (ie, 'loc', 'isp' or 'org'). + * + * @return array + */ + public static function getMissingDatabases() + { + $result = array(); + foreach (self::getConfiguredUrls() as $key => $url) + { + if ($url !== false) + { + // if a database of the type does not exist, but there's a url to update, then + // a database is missing + $path = Piwik_UserCountry_LocationProvider_GeoIp::getPathToGeoIpDatabase( + Piwik_UserCountry_LocationProvider_GeoIp::$dbNames[$key]); + if ($path === false) + { + $result[] = $key; + } + } + } + return $result; + } + + /** + * Returns the extension of a URL used to update a GeoIP database, if it can be found. + */ + public static function getGeoIPUrlExtension( $url ) + { + // check for &suffix= query param that is special to MaxMind URLs + if (preg_match('/suffix=([^&]+)/', $url, $matches)) + { + return $matches[1]; + } + + // use basename of url + $filenameParts = explode('.', basename($url), 2); + if (count($filenameParts) > 1) + { + return end($filenameParts); + } + else + { + return reset($filenameParts); + } + } +} diff --git a/plugins/UserCountry/LocationProvider/GeoIp.php b/plugins/UserCountry/LocationProvider/GeoIp.php index 9c2d49a476..4cb0157169 100755 --- a/plugins/UserCountry/LocationProvider/GeoIp.php +++ b/plugins/UserCountry/LocationProvider/GeoIp.php @@ -17,6 +17,9 @@ */ abstract class Piwik_UserCountry_LocationProvider_GeoIp extends Piwik_UserCountry_LocationProvider { + /* For testing, use: 'http://piwik-team.s3.amazonaws.com/GeoLiteCity.dat.gz' */ + const GEO_LITE_URL = 'http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz'; + public static $geoIPDatabaseDir = 'misc'; /** @@ -176,10 +179,9 @@ abstract class Piwik_UserCountry_LocationProvider_GeoIp extends Piwik_UserCountr */ public static function getPathToGeoIpDatabase( $possibleFileNames ) { - $dir = PIWIK_INCLUDE_PATH.'/'.self::$geoIPDatabaseDir; foreach ($possibleFileNames as $filename) { - $path = $dir.'/'.$filename; + $path = self::getPathForGeoIpDatabase($filename); if (file_exists($path)) { return $path; @@ -188,6 +190,17 @@ abstract class Piwik_UserCountry_LocationProvider_GeoIp extends Piwik_UserCountr return false; } + /** + * Returns full path for a GeoIP database managed by Piwik. + * + * @param string $filename Name of the .dat file. + * @return string + */ + public static function getPathForGeoIpDatabase( $filename ) + { + return PIWIK_INCLUDE_PATH.'/'.self::$geoIPDatabaseDir.'/'.$filename; + } + /** * Returns test IP used by isWorking and expected result. * @@ -206,6 +219,18 @@ abstract class Piwik_UserCountry_LocationProvider_GeoIp extends Piwik_UserCountr } return $result; } + + /** + * Returns true if there is a GeoIP database in the 'misc' directory. + * + * @return bool + */ + public static function isDatabaseInstalled() + { + return self::getPathToGeoIpDatabase(self::$dbNames['loc']) + || self::getPathToGeoIpDatabase(self::$dbNames['isp']) + || self::getPathToGeoIpDatabase(self::$dbNames['org']); + } } diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php index 91e6feaf05..cefbb66d87 100644 --- a/plugins/UserCountry/UserCountry.php +++ b/plugins/UserCountry/UserCountry.php @@ -10,6 +10,11 @@ * @package Piwik_UserCountry */ +/** + * @see plugins/UserCountry/GeoIPAutoUpdater.php + */ +require_once PIWIK_INCLUDE_PATH . '/plugins/UserCountry/GeoIPAutoUpdater.php'; + /** * * @package Piwik_UserCountry @@ -48,12 +53,35 @@ class Piwik_UserCountry extends Piwik_Plugin 'Goals.getReportsWithGoalMetrics' => 'getReportsWithGoalMetrics', 'API.getReportMetadata' => 'getReportMetadata', 'API.getSegmentsMetadata' => 'getSegmentsMetadata', + 'AssetManager.getCssFiles' => 'getCssFiles', 'AssetManager.getJsFiles' => 'getJsFiles', 'Tracker.getVisitorLocation' => 'getVisitorLocation', + 'TaskScheduler.getScheduledTasks' => 'getScheduledTasks', ); return $hooks; } + /** + * @param Piwik_Event_Notification $notification notification object + */ + function getScheduledTasks($notification) + { + $tasks = &$notification->getNotificationObject(); + + // add the auto updater task + $tasks[] = Piwik_UserCountry_GeoIPAutoUpdater::makeScheduledTask(); + } + + /** + * @param Piwik_Event_Notification $notification notification object + */ + function getCssFiles( $notification ) + { + $cssFiles = &$notification->getNotificationObject(); + + $cssFiles[] = "plugins/UserCountry/templates/styles.css"; + } + /** * @param Piwik_Event_Notification $notification notification object */ @@ -123,13 +151,10 @@ class Piwik_UserCountry extends Piwik_Plugin */ function addAdminMenu() { - if (Piwik::isUserIsSuperUser()) - { - Piwik_AddAdminMenu('UserCountry_Geolocation', - array('module' => 'UserCountry', 'action' => 'adminIndex'), - Piwik::isUserHasSomeAdminAccess(), - $order = 8); - } + Piwik_AddAdminMenu('UserCountry_Geolocation', + array('module' => 'UserCountry', 'action' => 'adminIndex'), + Piwik::isUserIsSuperUser(), + $order = 8); } /** diff --git a/plugins/UserCountry/templates/admin.js b/plugins/UserCountry/templates/admin.js index 8d10ca6e5c..1077039cba 100755 --- a/plugins/UserCountry/templates/admin.js +++ b/plugins/UserCountry/templates/admin.js @@ -6,8 +6,10 @@ */ $(document).ready(function() { + $('#geoip-download-progress,#geoip-updater-progressbar').progressbar({value: 1}); + // handle switch current location provider - $('.current-location-provider').change(function() { + $('.location-provider').change(function() { if (!$(this).is(':checked')) return; // only handle radio buttons that get checked var parent = $(this).parent(), @@ -60,4 +62,140 @@ $(document).ready(function() { return false; }); + + // geoip database wizard + var downloadNextChunk = function(action, thisId, progressBarId, cont, extraData, callback) + { + var data = { + module: 'UserCountry', + action: action, + token_auth: piwik.token_auth, + 'continue': cont ? 1 : 0, + }; + for (var k in extraData) + { + data[k] = extraData[k]; + } + + var ajaxRequest = new ajaxHelper(); + ajaxRequest.addParams(data, 'post'); + ajaxRequest.setCallback(function(response) { + if (!response || response.error) + { + callback(response); + } + else + { + // update progress bar + var newProgressVal = Math.ceil((response.current_size / response.expected_file_size) * 100); + newProgressVal = Math.min(newProgressVal, 100); + $('#'+progressBarId).progressbar('option', 'value', newProgressVal); + + // if incomplete, download next chunk, otherwise, show updater manager + if (newProgressVal < 100) + { + downloadNextChunk(action, thisId, progressBarId, true, extraData, callback); + } + else + { + callback(response); + } + } + }); + ajaxRequest.send(false); + }; + + $('#start-download-free-geoip').click(function() { + $('#geoipdb-screen1').hide("slide", {direction: "left"}, 800, function() { + $('#geoipdb-screen2-download').fadeIn(1000); + + // start download of free dbs + downloadNextChunk( + 'downloadFreeGeoIPDB', + 'geoipdb-screen2-download', + 'geoip-download-progress', + false, + {}, + function(response) { + if (response.error) + { + // on error, show error & stop downloading + $('#'+thisId).fadeOut(1000, function() { + $('#manage-geoip-dbs').html(response.error); + }); + } + else + { + $('#geoipdb-screen2-download').fadeOut(1000, function() { + $('#manage-geoip-dbs').html(response.next_screen); + }); + } + } + ); + }); + }); + + $('body').on('click', '#start-automatic-update-geoip', function() { + $('#geoipdb-screen1').hide("slide", {direction: "left"}, 800, function () { + $('#geoipdb-update-info').fadeIn(1000); + }); + }); + + $('body').on('click', '#update-geoip-links', function() { + $('#geoipdb-update-info-error').hide(); + + var currentDownloading = null, + updateGeoIPSuccess = function(response) + { + if (response && response.error) + { + $('#geoip-progressbar-container').hide(); + $('#geoipdb-update-info-error').html(response.error).show(); + } + else if (response && response.to_download) + { + var continuing = currentDownloading == response.to_download; + currentDownloading = response.to_download; + + // show progress bar w/ message + $('#geoip-updater-progressbar').progressbar('option', 'value', 1); + $('#geoip-updater-progressbar-label').html(response.to_download_label); + $('#geoip-progressbar-container').show(); + + // start/continue download + downloadNextChunk( + 'downloadMissingGeoIpDb', 'geoipdb-update-info', 'geoip-updater-progressbar', + continuing, {key: response.to_download}, updateGeoIPSuccess); + } + else + { + $('#geoipdb-update-info-error').hide(); + $('#geoip-updater-progressbar-label').html(''); + $('#geoip-progressbar-container').hide(); + + // fade in/out Done message + $('#done-updating-updater').fadeIn(1000, function() { + setTimeout(function() { + $('#done-updating-updater').fadeOut(1000); + }, 3000); + }); + } + }; + + // setup the auto-updater + var ajaxRequest = new ajaxHelper(); + ajaxRequest.addParams({ + period: $('#geoip-update-period-cell>input:checked').val() + }, 'get'); + ajaxRequest.addParams({ + module: 'UserCountry', + action: 'updateGeoIPLinks', + token_auth: piwik.token_auth, + loc_db: $('#geoip-location-db').val(), + isp_db: $('#geoip-isp-db').val(), + org_db: $('#geoip-org-db').val() + }, 'post'); + ajaxRequest.setCallback(updateGeoIPSuccess); + ajaxRequest.send(false); + }); }); diff --git a/plugins/UserCountry/templates/adminIndex.tpl b/plugins/UserCountry/templates/adminIndex.tpl index a4ddcfa9bc..ecf51a265d 100755 --- a/plugins/UserCountry/templates/adminIndex.tpl +++ b/plugins/UserCountry/templates/adminIndex.tpl @@ -22,7 +22,7 @@

 

{/if} - +
@@ -32,19 +32,19 @@
{'UserCountry_LocationProvider'|translate} {'General_Description'|translate}

- -
+ +

-

+

{if $provider.status eq 0} - {'General_NotInstalled'|translate} + {'General_NotInstalled'|translate} {elseif $provider.status eq 1} - {'General_Installed'|translate} + {'General_Installed'|translate} {elseif $provider.status eq 2} - {'General_Broken'|translate} + {'General_Broken'|translate} {/if}

@@ -93,5 +93,33 @@ +

{'UserCountry_GeoIPDatabases'|translate}

+ +{if $showGeoIPUpdateSection} +
+ +{if !$geoIPDatabasesInstalled} +
+

{'UserCountry_PiwikNotManagingGeoIPDBs'|translate}

+
+

{'UserCountry_IWantToDownloadFreeGeoIP'|translate}

+ +
+
+

{'UserCountry_IPurchasedGeoIPDBs'|translate}

+ +
+
+ +{/if} +{include file="UserCountry/templates/updaterSetup.tpl"} +{else} +

{'UserCountry_CannotSetupGeoIPAutoUpdating'|translate}

+{/if} +
+ {include file="CoreAdminHome/templates/footer.tpl"} diff --git a/plugins/UserCountry/templates/styles.css b/plugins/UserCountry/templates/styles.css new file mode 100755 index 0000000000..4ded571aa5 --- /dev/null +++ b/plugins/UserCountry/templates/styles.css @@ -0,0 +1,69 @@ +.locationProviderTable label { + font-size: 1.2em; +} + +input.location-provider { + cursor:pointer; +} + +span.is-installed { + color:green; +} + +span.is-broken { + color:red; +} + +.loc-provider-status { + margin-left:.5em; +} + +#manage-geoip-dbs { + width:900px; + height: 20em; +} + +#geoipdb-update-info tr input[type="text"],#geoipdb-screen2-update tr input[type="text"] { + width: 90%; +} + +#geoipdb-screen1>div { + display: inline-block; + vertical-align:top; +} + +#geoipdb-screen1>div>p { + font-size: 2em; + height: 4em; +} + +.geoipdb-column-1,.geoipdb-column-2 { + width:396px; +} +.geoipdb-column-1 { + margin-right: 50px; +} +.geoipdb-column-2 { + border-left: solid #999 1px; + padding-left: 50px; +} +.geoipdb-column-1>p { + padding-left: 20px; +} + +.error { + font-weight:bold; + color:red; + padding:4px 8px 4px 8px; +} + +#geoip-updater-progressbar-label { + float: left; + margin: -24px 24px; +} + +#geoip-progressbar-container,#geoipdb-update-info-error { + margin: 22px 24px; + display:inline-block; +} + diff --git a/plugins/UserCountry/templates/updaterSetup.tpl b/plugins/UserCountry/templates/updaterSetup.tpl new file mode 100755 index 0000000000..96d55b5f1a --- /dev/null +++ b/plugins/UserCountry/templates/updaterSetup.tpl @@ -0,0 +1,53 @@ +
+

{'UserCountry_GeoIPUpdaterInstructions'|translate:'':'':'':''}

+ {if $geoIPDatabasesInstalled} +

{'UserCountry_GeoIPUpdaterIntro'|translate}:

+ {/if} + + + + + + + + + + + + + + + + + + + + + + + + +
{'Live_GoalType'|translate}{'Actions_ColumnDownloadURL'|translate}
{'UserCountry_LocationDatabase'|translate} + {capture assign=locationHint} + {'UserCountry_LocationDatabaseHint'|translate} + {/capture} + {$locationHint|inlineHelp} +
{'UserCountry_ISPDatabase'|translate}
{'UserCountry_OrgDatabase'|translate}
{'General_Period'|translate} + + + + + +  
+

+ +

+
+ + + +
+
-- cgit v1.2.3