| <?php |
|
|
| |
| |
| |
| |
| |
| |
|
|
| namespace Piwik\Plugins\CoreAdminHome; |
|
|
| use Exception; |
| use Piwik\API\ResponseBuilder; |
| use Piwik\ArchiveProcessor\Rules; |
| use Piwik\Common; |
| use Piwik\Config; |
| use Piwik\DataTable\Renderer\Json; |
| use Piwik\Mail; |
| use Piwik\Menu\MenuTop; |
| use Piwik\Piwik; |
| use Piwik\Plugin; |
| use Piwik\Plugin\ControllerAdmin; |
| use Piwik\Changes\UserChanges; |
| use Piwik\Plugins\CorePluginsAdmin\CorePluginsAdmin; |
| use Piwik\Plugins\Marketplace\Marketplace; |
| use Piwik\Plugins\CustomVariables\CustomVariables; |
| use Piwik\Plugins\LanguagesManager\LanguagesManager; |
| use Piwik\Plugins\Login\PasswordVerifier; |
| use Piwik\Plugins\PrivacyManager\DoNotTrackHeaderChecker; |
| use Piwik\Plugins\SitesManager\API as APISitesManager; |
| use Piwik\Request; |
| use Piwik\Site; |
| use Piwik\Translation\Translator; |
| use Piwik\Url; |
| use Piwik\UrlHelper; |
| use Piwik\View; |
| use Piwik\Widget\WidgetsList; |
| use Piwik\SettingsPiwik; |
| use Piwik\Plugins\UsersManager\Model as UsersModel; |
| use Piwik\Plugins\UsersManager\UserPreferences; |
|
|
| class Controller extends ControllerAdmin |
| { |
| |
| |
| |
| private $translator; |
|
|
| |
| private $optOutManager; |
|
|
| |
| private $passwordVerify; |
|
|
| public function __construct(Translator $translator, OptOutManager $optOutManager, PasswordVerifier $passwordVerify) |
| { |
| $this->translator = $translator; |
| $this->optOutManager = $optOutManager; |
| $this->passwordVerify = $passwordVerify; |
|
|
| parent::__construct(); |
| } |
|
|
| public function home() |
| { |
| $isInternetEnabled = SettingsPiwik::isInternetEnabled(); |
|
|
| $isMarketplaceEnabled = Marketplace::isMarketplaceEnabled(); |
| $isFeedbackEnabled = Plugin\Manager::getInstance()->isPluginLoaded('Feedback'); |
| $widgetsList = WidgetsList::get(); |
|
|
| if ($isInternetEnabled && $isMarketplaceEnabled) { |
| $this->securityPolicy->addPolicy('img-src', '*.matomo.org'); |
| } |
|
|
| $hasDonateForm = $widgetsList->isDefined('CoreHome', 'getDonateForm'); |
| $hasPiwikBlog = $widgetsList->isDefined('RssWidget', 'rssPiwik'); |
| $hasPremiumFeatures = $widgetsList->isDefined('Marketplace', 'getPremiumFeatures'); |
| $hasNewPlugins = $widgetsList->isDefined('Marketplace', 'getNewPlugins'); |
| $hasDiagnostics = $widgetsList->isDefined('Installation', 'getSystemCheck'); |
| $hasTrackingFailures = $widgetsList->isDefined('CoreAdminHome', 'getTrackingFailures'); |
| $hasQuickLinks = $widgetsList->isDefined('CoreHome', 'quickLinks'); |
| $hasSystemSummary = $widgetsList->isDefined('CoreHome', 'getSystemSummary'); |
|
|
| return $this->renderTemplate('home', array( |
| 'isInternetEnabled' => $isInternetEnabled, |
| 'isMarketplaceEnabled' => $isMarketplaceEnabled, |
| 'hasPremiumFeatures' => $hasPremiumFeatures, |
| 'hasNewPlugins' => $hasNewPlugins, |
| 'isFeedbackEnabled' => $isFeedbackEnabled, |
| 'hasDonateForm' => $hasDonateForm, |
| 'hasPiwikBlog' => $hasPiwikBlog, |
| 'hasDiagnostics' => $hasDiagnostics, |
| 'hasTrackingFailures' => $hasTrackingFailures, |
| 'hasQuickLinks' => $hasQuickLinks, |
| 'hasSystemSummary' => $hasSystemSummary, |
| )); |
| } |
|
|
| public function index() |
| { |
| $this->redirectToIndex('UsersManager', 'userSettings'); |
| return; |
| } |
|
|
| public function trackingFailures() |
| { |
| Piwik::checkUserHasSomeAdminAccess(); |
|
|
| return $this->renderTemplate('trackingFailures'); |
| } |
|
|
| public function generalSettings() |
| { |
| Piwik::checkUserHasSuperUserAccess(); |
|
|
| $view = new View('@CoreAdminHome/generalSettings'); |
| $this->handleGeneralSettingsAdmin($view); |
|
|
| $view->trustedHosts = array_values(Url::getTrustedHostsFromConfig()); |
| $logo = new CustomLogo(); |
| $view->branding = array('use_custom_logo' => $logo->isEnabled()); |
| $view->fileUploadEnabled = $logo->isFileUploadEnabled(); |
| $view->logosWriteable = $logo->isCustomLogoWritable(); |
| $view->customLogoEnabled = $logo->isCustomLogoFeatureEnabled(); |
| $view->hasUserLogo = CustomLogo::hasUserLogo(); |
| $view->pathUserLogo = CustomLogo::getPathUserLogo(); |
| $view->hasUserFavicon = CustomLogo::hasUserFavicon(); |
| $view->pathUserFavicon = CustomLogo::getPathUserFavicon(); |
| $view->pathUserLogoSmall = CustomLogo::getPathUserLogoSmall(); |
| $view->pathUserLogoSVG = CustomLogo::getPathUserSvgLogo(); |
| $view->pathUserLogoDirectory = realpath(dirname($view->pathUserLogo) . '/'); |
| $view->mailTypes = array( |
| '' => '', |
| 'Plain' => 'Plain', |
| 'Login' => 'Login', |
| 'Cram-md5' => 'Cram-md5', |
| ); |
| $view->mailEncryptions = array( |
| '' => 'auto', |
| 'ssl' => 'SSL', |
| 'tls' => 'TLS', |
| 'none' => 'none', |
| ); |
| $mail = new Mail(); |
| $view->mailHost = $mail->getMailHost(); |
|
|
| $view->language = LanguagesManager::getLanguageCodeForCurrentUser(); |
| $this->setBasicVariablesView($view); |
| return $view->render(); |
| } |
|
|
| public function setMailSettings() |
| { |
| Piwik::checkUserHasSuperUserAccess(); |
|
|
| if (!self::isGeneralSettingsAdminEnabled()) { |
| |
| return ''; |
| } |
|
|
| if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') { |
| throw new Exception('Invalid HTTP method.'); |
| } |
|
|
| $response = new ResponseBuilder('json'); |
| try { |
| $this->checkTokenInUrl(); |
|
|
| $request = Request::fromPost(); |
|
|
| |
| $login = Piwik::getCurrentUserLogin(); |
| if (Piwik::doesUserRequirePasswordConfirmation($login)) { |
| $passwordConfirmation = $request->getStringParameter('passwordConfirmation', ''); |
| if ( |
| $passwordConfirmation === '' |
| || !$this->passwordVerify->isPasswordCorrect($login, $passwordConfirmation) |
| ) { |
| throw new Exception(Piwik::translate('UsersManager_CurrentPasswordNotCorrect')); |
| } |
| } |
|
|
| |
| $mail = []; |
| $mail['transport'] = $request->getBoolParameter('mailUseSmtp') ? 'smtp' : ''; |
| $mail['port'] = $request->getStringParameter('mailPort', ''); |
| $mail['host'] = $request->getStringParameter('mailHost', ''); |
| $mail['type'] = $request->getStringParameter('mailType', ''); |
| $mail['username'] = $request->getStringParameter('mailUsername', ''); |
| $mail['password'] = $request->getStringParameter('mailPassword', ''); |
|
|
| if (!array_key_exists('mailPassword', $request->getParameters()) && Config::getInstance()->mail['host'] === $mail['host']) { |
| |
| $mail['password'] = Config::getInstance()->mail['password']; |
| } |
|
|
| $mail['encryption'] = $request->getStringParameter('mailEncryption', ''); |
|
|
| Config::getInstance()->mail = $mail; |
|
|
| $general = Config::getInstance()->General; |
| $general['noreply_email_name'] = $request->getStringParameter('mailFromName', ''); |
|
|
| $mailFrom = $request->getStringParameter('mailFromAddress', ''); |
| if (empty($mailFrom)) { |
| $mailFrom = 'noreply@{DOMAIN}'; |
| } |
| if (!Piwik::isValidEmailString($mailFrom) && !Common::stringEndsWith($mailFrom, '@{DOMAIN}')) { |
| throw new Exception(Piwik::translate('CoreAdminHome_ErrorEmailFromAddressNotValid')); |
| } |
| $general['noreply_email_address'] = $mailFrom; |
| Config::getInstance()->General = $general; |
|
|
| Config::getInstance()->forceSave(); |
|
|
| $toReturn = $response->getResponse(); |
| } catch (Exception $e) { |
| $toReturn = $response->getResponseException($e); |
| } |
|
|
| return $toReturn; |
| } |
|
|
| |
| |
| |
| |
| public function trackingCodeGenerator() |
| { |
| Piwik::checkUserHasSomeViewAccess(); |
|
|
| $view = new View('@CoreAdminHome/trackingCodeGenerator'); |
| $this->setBasicVariablesView($view); |
| $view->topMenu = MenuTop::getInstance()->getMenu(); |
|
|
| $viewableIdSites = APISitesManager::getInstance()->getSitesIdWithAtLeastViewAccess(); |
|
|
| $defaultIdSite = reset($viewableIdSites); |
| $view->idSite = $this->idSite ?: $defaultIdSite; |
|
|
| if ($view->idSite) { |
| try { |
| $view->siteName = Site::getNameFor($view->idSite); |
| $view->siteNameDecoded = Common::unsanitizeInputValue($view->siteName); |
| } catch (Exception $e) { |
| |
| } |
| } |
|
|
| $view->defaultReportSiteName = Site::getNameFor($view->idSite); |
| $view->defaultSiteRevenue = Site::getCurrencySymbolFor($view->idSite); |
| $view->maxCustomVariables = 0; |
|
|
| if (Plugin\Manager::getInstance()->isPluginActivated('CustomVariables')) { |
| $view->maxCustomVariables = CustomVariables::getNumUsableCustomVariables(); |
| } |
|
|
| $view->defaultSite = array('id' => $view->idSite, 'name' => $view->defaultReportSiteName); |
| $view->defaultSiteDecoded = [ |
| 'id' => $view->idSite, |
| 'name' => Common::unsanitizeInputValue($view->defaultReportSiteName), |
| ]; |
|
|
| $allUrls = APISitesManager::getInstance()->getSiteUrlsFromId($view->idSite); |
| if (isset($allUrls[1])) { |
| $aliasUrl = $allUrls[1]; |
| } else { |
| $aliasUrl = 'x.domain.com'; |
| } |
| $view->defaultReportSiteAlias = $aliasUrl; |
|
|
| $mainUrl = Site::getMainUrlFor($view->idSite); |
| $view->defaultReportSiteDomain = @parse_url($mainUrl, PHP_URL_HOST); |
|
|
| $dntChecker = new DoNotTrackHeaderChecker(); |
| $view->serverSideDoNotTrackEnabled = $dntChecker->isActive(); |
|
|
| return $view->render(); |
| } |
|
|
| |
| |
| |
| public function optOut() |
| { |
| return $this->optOutManager->getOptOutViewIframe()->render(); |
| } |
|
|
| |
| |
| |
| |
| |
| public function optOutJS(): string |
| { |
| Common::sendHeader('Content-Type: application/javascript; charset=utf-8'); |
| Common::sendHeader('Cache-Control: no-store'); |
| return $this->optOutManager->getOptOutJS(); |
| } |
|
|
| public function uploadCustomLogo() |
| { |
| Piwik::checkUserHasSuperUserAccess(); |
| $this->checkTokenInUrl(); |
|
|
| $logo = new CustomLogo(); |
|
|
| if (! $logo->isCustomLogoFeatureEnabled()) { |
| return '0'; |
| } |
|
|
| $successLogo = $logo->uploadLogoToTempFolder(); |
| $successFavicon = $logo->uploadFaviconToTempFolder(); |
|
|
| $response = []; |
|
|
| if ($successLogo) { |
| $response['logo'] = $logo->getTempUserLogoBase64(); |
| } |
|
|
| if ($successFavicon) { |
| $response['favicon'] = $logo->getTempUserFaviconBase64(); |
| } |
|
|
| Json::sendHeaderJSON(); |
| return json_encode($response); |
| } |
|
|
| public static function isGeneralSettingsAdminEnabled() |
| { |
| return (bool) Config::getInstance()->General['enable_general_settings_admin']; |
| } |
|
|
| private function handleGeneralSettingsAdmin($view) |
| { |
| |
| $view->isGeneralSettingsAdminEnabled = self::isGeneralSettingsAdminEnabled(); |
| $view->isMultiServerEnvironment = SettingsPiwik::isMultiServerEnvironment(); |
| $view->isPluginsAdminEnabled = CorePluginsAdmin::isPluginsAdminEnabled(); |
| if ($view->isGeneralSettingsAdminEnabled) { |
| $this->displayWarningIfConfigFileNotWritable(); |
| } |
|
|
| $enableBrowserTriggerArchiving = Rules::isBrowserTriggerEnabled(); |
| $todayArchiveTimeToLive = Rules::getTodayArchiveTimeToLive(); |
| $showWarningCron = false; |
| if ( |
| !$enableBrowserTriggerArchiving |
| && $todayArchiveTimeToLive < 3600 |
| ) { |
| $showWarningCron = true; |
| } |
| $view->showWarningCron = $showWarningCron; |
| $view->todayArchiveTimeToLive = $todayArchiveTimeToLive; |
| $view->todayArchiveTimeToLiveDefault = Rules::getTodayArchiveTimeToLiveDefault(); |
| $view->enableBrowserTriggerArchiving = $enableBrowserTriggerArchiving; |
| $view->showSegmentArchiveTriggerInfo = Rules::isBrowserArchivingAvailableForSegments(); |
|
|
| $mail = Config::getInstance()->mail; |
| $mail['noreply_email_address'] = Config::getInstance()->General['noreply_email_address']; |
| $mail['noreply_email_name'] = Config::getInstance()->General['noreply_email_name']; |
| $mail['password'] = !empty($mail['password']) ? '*****' : ''; |
| $view->mail = $mail; |
| } |
|
|
| |
| |
| |
| public function whatIsNew() |
| { |
| Piwik::checkUserHasSomeViewAccess(); |
| Piwik::checkUserIsNotAnonymous(); |
|
|
| $model = new UsersModel(); |
| $user = $model->getUser(Piwik::getCurrentUserLogin()); |
| if (!empty($user)) { |
| $userChanges = new UserChanges($user); |
| $changes = $this->enrichChangesForWhatIsNew($userChanges->getChanges()); |
| return $this->renderTemplate('whatIsNew', ['changes' => $changes]); |
| } else { |
| throw new \Exception('Unable to getUser() when attempting to show whatIsNew'); |
| } |
| } |
|
|
| |
| |
| |
| private function enrichChangesForWhatIsNew(array $changes): array |
| { |
| $pluginManager = Plugin\Manager::getInstance(); |
|
|
| foreach ($changes as &$change) { |
| $pluginName = $change['plugin_name'] ?? ''; |
| $change['showPluginPrefix'] = !empty($pluginName) |
| && !$pluginManager->isPluginBundledWithCore($pluginName); |
|
|
| if (!empty($change['link'])) { |
| $defaultIdSite = $this->getDefaultIdSiteForWhatIsNewLinks(); |
| if (!empty($defaultIdSite)) { |
| $change['link'] = $this->normalizeWhatIsNewLink($change['link'], $defaultIdSite); |
| } |
| } |
| } |
| unset($change); |
|
|
| return $changes; |
| } |
|
|
| private function getDefaultIdSiteForWhatIsNewLinks(): ?int |
| { |
| $userPreferences = new UserPreferences(); |
| $defaultReport = $userPreferences->getDefaultReport(); |
|
|
| if (is_numeric($defaultReport)) { |
| return (int) $defaultReport; |
| } |
|
|
| $defaultWebsiteId = $userPreferences->getDefaultWebsiteId(); |
| if (is_numeric($defaultWebsiteId)) { |
| return (int) $defaultWebsiteId; |
| } |
|
|
| return null; |
| } |
|
|
| private function normalizeWhatIsNewLink(string $link, int $defaultIdSite): string |
| { |
| if (!$this->isInternalWhatIsNewLink($link)) { |
| return $link; |
| } |
|
|
| |
| |
| if (strpos($link, '/index.php') === 0) { |
| $link = substr($link, 1); |
| } |
|
|
| $parsedLink = @parse_url($link); |
| if (!is_array($parsedLink)) { |
| return $link; |
| } |
|
|
| $query = $parsedLink['query'] ?? ''; |
| $parsedLink['query'] = $this->replaceIdSiteInQueryString($query, $defaultIdSite); |
|
|
| $fragment = $parsedLink['fragment'] ?? ''; |
| $parsedLink['fragment'] = $this->replaceIdSiteInFragment($fragment, $defaultIdSite); |
|
|
| if ($query === $parsedLink['query'] && $fragment === $parsedLink['fragment']) { |
| return $link; |
| } |
|
|
| return UrlHelper::getParseUrlReverse($parsedLink) ?: $link; |
| } |
|
|
| private function replaceIdSiteInFragment(string $fragment, int $idSite): string |
| { |
| $fragmentPrefix = ''; |
| $fragmentQuery = ''; |
| if (strpos($fragment, '/?') === 0) { |
| $fragmentPrefix = '/?'; |
| $fragmentQuery = substr($fragment, 2); |
| } elseif (strpos($fragment, '?') === 0) { |
| $fragmentPrefix = '?'; |
| $fragmentQuery = substr($fragment, 1); |
| } |
|
|
| if (empty($fragmentPrefix)) { |
| return $fragment; |
| } |
|
|
| return $fragmentPrefix . $this->replaceIdSiteInQueryString($fragmentQuery, $idSite); |
| } |
|
|
| private function replaceIdSiteInQueryString(string $queryStr, int $idSite): string |
| { |
| $queryParams = UrlHelper::getArrayFromQueryString($queryStr); |
|
|
| if (!array_key_exists('idSite', $queryParams)) { |
| return $queryStr; |
| } |
|
|
| $queryParams['idSite'] = $idSite; |
| return Url::getQueryStringFromParameters($queryParams); |
| } |
|
|
| private function isInternalWhatIsNewLink(string $link): bool |
| { |
| return strpos($link, 'index.php') === 0 || strpos($link, '/index.php') === 0; |
| } |
| } |
|
|