488 lines
16 KiB
PHP
488 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* Piwik - free/libre analytics platform
|
|
*
|
|
* @link http://piwik.org
|
|
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*/
|
|
|
|
namespace Piwik\Plugins\Marketplace;
|
|
|
|
use Piwik\Common;
|
|
use Piwik\Date;
|
|
use Piwik\Filesystem;
|
|
use Piwik\Log;
|
|
use Piwik\Nonce;
|
|
use Piwik\Notification;
|
|
use Piwik\Piwik;
|
|
use Piwik\Plugin;
|
|
use Piwik\Plugins\CorePluginsAdmin\Controller as PluginsController;
|
|
use Piwik\Plugins\CorePluginsAdmin\CorePluginsAdmin;
|
|
use Piwik\Plugins\CorePluginsAdmin\PluginInstaller;
|
|
use Piwik\Plugins\Marketplace\Input\Mode;
|
|
use Piwik\Plugins\Marketplace\Input\PluginName;
|
|
use Piwik\Plugins\Marketplace\Input\PurchaseType;
|
|
use Piwik\Plugins\Marketplace\Input\Sort;
|
|
use Piwik\ProxyHttp;
|
|
use Piwik\SettingsPiwik;
|
|
use Piwik\Url;
|
|
use Piwik\View;
|
|
use Exception;
|
|
|
|
class Controller extends \Piwik\Plugin\ControllerAdmin
|
|
{
|
|
const UPDATE_NONCE = 'Marketplace.updatePlugin';
|
|
const INSTALL_NONCE = 'Marketplace.installPlugin';
|
|
|
|
/**
|
|
* @var LicenseKey
|
|
*/
|
|
private $licenseKey;
|
|
/**
|
|
* @var Plugins
|
|
*/
|
|
private $plugins;
|
|
|
|
/**
|
|
* @var Api\Client
|
|
*/
|
|
private $marketplaceApi;
|
|
|
|
/**
|
|
* @var Consumer
|
|
*/
|
|
private $consumer;
|
|
|
|
/**
|
|
* @var PluginInstaller
|
|
*/
|
|
private $pluginInstaller;
|
|
|
|
/**
|
|
* @var Plugin\Manager
|
|
*/
|
|
private $pluginManager;
|
|
|
|
/**
|
|
* @var Environment
|
|
*/
|
|
private $environment;
|
|
|
|
public function __construct(LicenseKey $licenseKey, Plugins $plugins, Api\Client $marketplaceApi, Consumer $consumer, PluginInstaller $pluginInstaller, Environment $environment)
|
|
{
|
|
$this->licenseKey = $licenseKey;
|
|
$this->plugins = $plugins;
|
|
$this->marketplaceApi = $marketplaceApi;
|
|
$this->consumer = $consumer;
|
|
$this->pluginInstaller = $pluginInstaller;
|
|
$this->pluginManager = Plugin\Manager::getInstance();
|
|
$this->environment = $environment;
|
|
|
|
parent::__construct();
|
|
}
|
|
|
|
public function subscriptionOverview()
|
|
{
|
|
Piwik::checkUserHasSuperUserAccess();
|
|
|
|
// we want to make sure to fetch the latest results, eg in case user has purchased a subscription meanwhile
|
|
// this is also like a self-repair to clear the caches :)
|
|
$this->marketplaceApi->clearAllCacheEntries();
|
|
$this->consumer->clearCache();
|
|
// invalidate cache for plugin/manager
|
|
Plugin\Manager::getLicenseCache()->flushAll();
|
|
|
|
$hasLicenseKey = $this->licenseKey->has();
|
|
|
|
$consumer = $this->consumer->getConsumer();
|
|
|
|
$subscriptions = array();
|
|
$loginUrl = '';
|
|
|
|
if (!empty($consumer['loginUrl'])) {
|
|
$loginUrl = $consumer['loginUrl'];
|
|
}
|
|
|
|
if (!empty($consumer['licenses'])) {
|
|
foreach ($consumer['licenses'] as $subscription) {
|
|
$subscription['start'] = $this->getPrettyLongDate($subscription['startDate']);
|
|
$subscription['end'] = $this->getPrettyLongDate($subscription['endDate']);
|
|
$subscription['nextPayment'] = $this->getPrettyLongDate($subscription['nextPaymentDate']);
|
|
$subscriptions[] = $subscription;
|
|
}
|
|
}
|
|
|
|
return $this->renderTemplate('@Marketplace/subscription-overview', array(
|
|
'hasLicenseKey' => $hasLicenseKey,
|
|
'subscriptions' => $subscriptions,
|
|
'loginUrl' => $loginUrl,
|
|
'numUsers' => $this->environment->getNumUsers()
|
|
));
|
|
}
|
|
|
|
private function getPrettyLongDate($date)
|
|
{
|
|
if (empty($date)) {
|
|
return '';
|
|
}
|
|
|
|
return Date::factory($date)->getLocalized(Date::DATE_FORMAT_LONG);
|
|
}
|
|
|
|
public function pluginDetails()
|
|
{
|
|
$view = $this->configureViewAndCheckPermission('@Marketplace/plugin-details');
|
|
|
|
$pluginName = new PluginName();
|
|
$pluginName = $pluginName->getPluginName();
|
|
|
|
$activeTab = Common::getRequestVar('activeTab', '', 'string');
|
|
if ('changelog' !== $activeTab) {
|
|
$activeTab = '';
|
|
}
|
|
|
|
try {
|
|
$plugin = $this->plugins->getPluginInfo($pluginName);
|
|
|
|
if (empty($plugin['name'])) {
|
|
throw new Exception('Plugin does not exist');
|
|
}
|
|
} catch (Exception $e) {
|
|
$plugin = null;
|
|
$view->errorMessage = $e->getMessage();
|
|
}
|
|
|
|
$view->plugin = $plugin;
|
|
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
|
|
$view->installNonce = Nonce::getNonce(static::INSTALL_NONCE);
|
|
$view->updateNonce = Nonce::getNonce(static::UPDATE_NONCE);
|
|
$view->activeTab = $activeTab;
|
|
$view->isAutoUpdatePossible = SettingsPiwik::isAutoUpdatePossible();
|
|
$view->isAutoUpdateEnabled = SettingsPiwik::isAutoUpdateEnabled();
|
|
$view->numUsers = $this->environment->getNumUsers();
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
public function download()
|
|
{
|
|
Piwik::checkUserHasSuperUserAccess();
|
|
|
|
$this->dieIfPluginsAdminIsDisabled();
|
|
|
|
$pluginName = new PluginName();
|
|
$pluginName = $pluginName->getPluginName();
|
|
|
|
Nonce::checkNonce($pluginName);
|
|
|
|
$filename = $pluginName . '.zip';
|
|
|
|
try {
|
|
$pathToPlugin = $this->marketplaceApi->download($pluginName);
|
|
ProxyHttp::serverStaticFile($pathToPlugin, 'application/zip', $expire = 0, $start = false, $end = false, $filename);
|
|
} catch (Exception $e) {
|
|
Common::sendResponseCode(500);
|
|
Log::warning('Could not download file . ' . $e->getMessage());
|
|
}
|
|
|
|
if (!empty($pathToPlugin)) {
|
|
Filesystem::deleteFileIfExists($pathToPlugin);
|
|
}
|
|
}
|
|
|
|
public function overview()
|
|
{
|
|
$view = $this->configureViewAndCheckPermission('@Marketplace/overview');
|
|
|
|
$show = Common::getRequestVar('show', 'plugins', 'string');
|
|
$query = Common::getRequestVar('query', '', 'string', $_POST);
|
|
|
|
$sort = new Sort();
|
|
$sort = $sort->getSort();
|
|
|
|
$mode = new Mode();
|
|
$mode = $mode->getMode();
|
|
|
|
// we're fetching all available plugins to decide which tabs need to be shown in the UI and to know the number
|
|
// of total available plugins
|
|
$allPlugins = $this->plugins->getAllPlugins();
|
|
$allThemes = $this->plugins->getAllThemes();
|
|
$paidPlugins = $this->plugins->getAllPaidPlugins();
|
|
|
|
$showThemes = ($show === 'themes');
|
|
$showPlugins = !$showThemes;
|
|
$showPaid = ($show === 'premium');
|
|
$showAll = !$showPaid;
|
|
|
|
if ($showPlugins && $showPaid) {
|
|
$type = PurchaseType::TYPE_PAID;
|
|
$view->numAvailablePlugins = count($paidPlugins);
|
|
} elseif ($showPlugins && $showAll) {
|
|
$type = PurchaseType::TYPE_ALL;
|
|
$view->numAvailablePlugins = count($allPlugins);
|
|
} else {
|
|
$type = PurchaseType::TYPE_ALL;
|
|
$view->numAvailablePlugins = count($allThemes);
|
|
}
|
|
|
|
$pluginsToShow = $this->plugins->searchPlugins($query, $sort, $showThemes, $type);
|
|
|
|
$paidPluginsToInstallAtOnce = array();
|
|
if (SettingsPiwik::isAutoUpdatePossible()) {
|
|
foreach ($paidPlugins as $paidPlugin) {
|
|
if ($this->canPluginBeInstalled($paidPlugin)
|
|
|| ($this->pluginManager->isPluginInstalled($paidPlugin['name'])
|
|
&& !$this->pluginManager->isPluginActivated($paidPlugin['name']))) {
|
|
$paidPluginsToInstallAtOnce[] = $paidPlugin['name'];
|
|
}
|
|
}
|
|
}
|
|
|
|
$view->paidPluginsToInstallAtOnce = $paidPluginsToInstallAtOnce;
|
|
$view->pluginsToShow = $pluginsToShow;
|
|
$view->isValidConsumer = $this->consumer->isValidConsumer();
|
|
$view->paidPlugins = $paidPlugins;
|
|
$view->freePlugins = $allPlugins;
|
|
$view->themes = $allThemes;
|
|
$view->showThemes = $showThemes;
|
|
$view->showPlugins = $showPlugins;
|
|
$view->showFree = $showAll;
|
|
$view->showPaid = $showPaid;
|
|
$view->pluginType = $show;
|
|
$view->pluginTypeOptions = array(
|
|
'plugins' => Piwik::translate('General_Plugins'),
|
|
'premium' => Piwik::translate('Marketplace_PaidPlugins'),
|
|
'themes' => Piwik::translate('CorePluginsAdmin_Themes')
|
|
);
|
|
$view->pluginSortOptions = array(
|
|
Sort::METHOD_LAST_UPDATED => Piwik::translate('Marketplace_SortByLastUpdated'),
|
|
Sort::METHOD_POPULAR => Piwik::translate('Marketplace_SortByPopular'),
|
|
Sort::METHOD_NEWEST => Piwik::translate('Marketplace_SortByNewest'),
|
|
Sort::METHOD_ALPHA => Piwik::translate('Marketplace_SortByAlpha'),
|
|
);
|
|
$view->mode = $mode;
|
|
$view->query = $query;
|
|
$view->sort = $sort;
|
|
$view->hasLicenseKey = $this->licenseKey->has();
|
|
$view->hasSomeAdminAccess = Piwik::isUserHasSomeAdminAccess();
|
|
$view->installNonce = Nonce::getNonce(static::INSTALL_NONCE);
|
|
$view->updateNonce = Nonce::getNonce(static::UPDATE_NONCE);
|
|
$view->deactivateNonce = Nonce::getNonce(PluginsController::DEACTIVATE_NONCE);
|
|
$view->activateNonce = Nonce::getNonce(PluginsController::ACTIVATE_NONCE);
|
|
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
|
|
$view->isPluginsAdminEnabled = CorePluginsAdmin::isPluginsAdminEnabled();
|
|
$view->isAutoUpdatePossible = SettingsPiwik::isAutoUpdatePossible();
|
|
$view->isAutoUpdateEnabled = SettingsPiwik::isAutoUpdateEnabled();
|
|
$view->isPluginUploadEnabled = CorePluginsAdmin::isPluginUploadEnabled();
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
public function installAllPaidPlugins()
|
|
{
|
|
Piwik::checkUserHasSuperUserAccess();
|
|
|
|
$this->dieIfPluginsAdminIsDisabled();
|
|
Plugin\ControllerAdmin::displayWarningIfConfigFileNotWritable();
|
|
|
|
Nonce::checkNonce(static::INSTALL_NONCE);
|
|
|
|
$paidPlugins = $this->plugins->getAllPaidPlugins();
|
|
|
|
$hasErrors = false;
|
|
foreach ($paidPlugins as $paidPlugin) {
|
|
if (!$this->canPluginBeInstalled($paidPlugin)) {
|
|
continue;
|
|
}
|
|
|
|
$pluginName = $paidPlugin['name'];
|
|
|
|
try {
|
|
|
|
$this->pluginInstaller->installOrUpdatePluginFromMarketplace($pluginName);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$notification = new Notification($e->getMessage());
|
|
$notification->context = Notification::CONTEXT_ERROR;
|
|
if (method_exists($e, 'isHtmlMessage') && $e->isHtmlMessage()) {
|
|
$notification->raw = true;
|
|
}
|
|
Notification\Manager::notify('Marketplace_Install' . $pluginName, $notification);
|
|
|
|
$hasErrors = true;
|
|
}
|
|
}
|
|
|
|
if ($hasErrors) {
|
|
Url::redirectToReferrer();
|
|
return;
|
|
}
|
|
|
|
$dependency = new Plugin\Dependency();
|
|
|
|
for ($i = 0; $i <= 10; $i++) {
|
|
foreach ($paidPlugins as $index => $paidPlugin) {
|
|
if (empty($paidPlugin)) {
|
|
continue;
|
|
}
|
|
|
|
$pluginName = $paidPlugin['name'];
|
|
|
|
if ($this->pluginManager->isPluginActivated($pluginName)) {
|
|
// we do not use unset since it might skip a plugin afterwards when removing index
|
|
$paidPlugins[$index] = null;
|
|
continue;
|
|
}
|
|
|
|
if (!$this->pluginManager->isPluginInFilesystem($pluginName)) {
|
|
$paidPlugins[$index] = null;
|
|
continue;
|
|
}
|
|
|
|
if (empty($paidPlugin['require'])
|
|
|| !$dependency->hasDependencyToDisabledPlugin($paidPlugin['require'])) {
|
|
|
|
$paidPlugins[$index] = null;
|
|
|
|
try {
|
|
$this->pluginManager->activatePlugin($pluginName);
|
|
} catch (Exception $e) {
|
|
|
|
$hasErrors = true;
|
|
$notification = new Notification($e->getMessage());
|
|
$notification->context = Notification::CONTEXT_ERROR;
|
|
Notification\Manager::notify('Marketplace_Install' . $pluginName, $notification);
|
|
}
|
|
}
|
|
}
|
|
|
|
$paidPlugins = array_filter($paidPlugins);
|
|
}
|
|
|
|
if ($hasErrors) {
|
|
$notification = new Notification(Piwik::translate('Marketplace_OnlySomePaidPluginsInstalledAndActivated'));
|
|
$notification->context = Notification::CONTEXT_INFO;
|
|
} else {
|
|
$notification = new Notification(Piwik::translate('Marketplace_AllPaidPluginsInstalledAndActivated'));
|
|
$notification->context = Notification::CONTEXT_SUCCESS;
|
|
}
|
|
|
|
Notification\Manager::notify('Marketplace_InstallAll', $notification);
|
|
|
|
Url::redirectToReferrer();
|
|
}
|
|
|
|
public function updatePlugin()
|
|
{
|
|
$view = $this->createUpdateOrInstallView('updatePlugin', static::UPDATE_NONCE);
|
|
return $view->render();
|
|
}
|
|
|
|
public function installPlugin()
|
|
{
|
|
$view = $this->createUpdateOrInstallView('installPlugin', static::INSTALL_NONCE);
|
|
$view->nonce = Nonce::getNonce(PluginsController::ACTIVATE_NONCE);
|
|
|
|
return $view->render();
|
|
}
|
|
|
|
private function createUpdateOrInstallView($template, $nonceName)
|
|
{
|
|
Piwik::checkUserHasSuperUserAccess();
|
|
$this->dieIfPluginsAdminIsDisabled();
|
|
$this->displayWarningIfConfigFileNotWritable();
|
|
|
|
$plugins = $this->getPluginNameIfNonceValid($nonceName);
|
|
|
|
$view = new View('@Marketplace/' . $template);
|
|
$this->setBasicVariablesView($view);
|
|
$view->errorMessage = '';
|
|
|
|
$pluginInfos = [];
|
|
foreach ($plugins as $pluginName) {
|
|
$pluginInfos[] = $this->plugins->getPluginInfo($pluginName);
|
|
|
|
try {
|
|
$this->pluginInstaller->installOrUpdatePluginFromMarketplace($pluginName);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$notification = new Notification($e->getMessage());
|
|
$notification->context = Notification::CONTEXT_ERROR;
|
|
$notification->type = Notification::TYPE_PERSISTENT;
|
|
$notification->flags = Notification::FLAG_CLEAR;
|
|
if (method_exists($e, 'isHtmlMessage') && $e->isHtmlMessage()) {
|
|
$notification->raw = true;
|
|
}
|
|
Notification\Manager::notify('CorePluginsAdmin_InstallPlugin', $notification);
|
|
|
|
Url::redirectToReferrer();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$view->plugins = $pluginInfos;
|
|
|
|
return $view;
|
|
}
|
|
|
|
private function getPluginNameIfNonceValid($nonceName)
|
|
{
|
|
$nonce = Common::getRequestVar('nonce', null, 'string');
|
|
|
|
if (!Nonce::verifyNonce($nonceName, $nonce)) {
|
|
throw new \Exception(Piwik::translate('General_ExceptionNonceMismatch'));
|
|
}
|
|
|
|
Nonce::discardNonce($nonceName);
|
|
|
|
$pluginName = Common::getRequestVar('pluginName', null, 'string');
|
|
|
|
$plugins = explode(',', $pluginName);
|
|
$plugins = array_map('trim', $plugins);
|
|
foreach ($plugins as $name) {
|
|
if (!$this->pluginManager->isValidPluginName($name)) {
|
|
throw new Exception('Invalid plugin name: ' . $name);
|
|
}
|
|
}
|
|
return $plugins;
|
|
}
|
|
|
|
private function dieIfPluginsAdminIsDisabled()
|
|
{
|
|
if (!CorePluginsAdmin::isPluginsAdminEnabled()) {
|
|
throw new \Exception('Enabling, disabling and uninstalling plugins has been disabled by Piwik admins.
|
|
Please contact your Piwik admins with your request so they can assist you.');
|
|
}
|
|
}
|
|
|
|
private function canPluginBeInstalled($plugin)
|
|
{
|
|
if (empty($plugin['isDownloadable'])) {
|
|
return false;
|
|
}
|
|
|
|
$pluginName = $plugin['name'];
|
|
|
|
$isAlreadyInstalled = $this->pluginManager->isPluginInstalled($pluginName)
|
|
|| $this->pluginManager->isPluginLoaded($pluginName)
|
|
|| $this->pluginManager->isPluginActivated($pluginName);
|
|
|
|
return !$isAlreadyInstalled;
|
|
}
|
|
|
|
protected function configureViewAndCheckPermission($template)
|
|
{
|
|
Piwik::checkUserIsNotAnonymous();
|
|
|
|
$view = new View($template);
|
|
$this->setBasicVariablesView($view);
|
|
$this->displayWarningIfConfigFileNotWritable();
|
|
|
|
$view->errorMessage = '';
|
|
|
|
return $view;
|
|
}
|
|
}
|