add icons for Character groups
This commit is contained in:
commit
2d9a41a5fe
3461 changed files with 594457 additions and 0 deletions
481
www/analytics/plugins/CorePluginsAdmin/Controller.php
Normal file
481
www/analytics/plugins/CorePluginsAdmin/Controller.php
Normal file
|
|
@ -0,0 +1,481 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
use Piwik\API\Request;
|
||||
use Piwik\Common;
|
||||
use Piwik\Filechecks;
|
||||
use Piwik\Filesystem;
|
||||
use Piwik\Nonce;
|
||||
use Piwik\Notification;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugin;
|
||||
use Piwik\Settings\Manager as SettingsManager;
|
||||
use Piwik\Url;
|
||||
use Piwik\View;
|
||||
use Piwik\Version;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
*/
|
||||
class Controller extends Plugin\ControllerAdmin
|
||||
{
|
||||
const UPDATE_NONCE = 'CorePluginsAdmin.updatePlugin';
|
||||
const INSTALL_NONCE = 'CorePluginsAdmin.installPlugin';
|
||||
const ACTIVATE_NONCE = 'CorePluginsAdmin.activatePlugin';
|
||||
const DEACTIVATE_NONCE = 'CorePluginsAdmin.deactivatePlugin';
|
||||
const UNINSTALL_NONCE = 'CorePluginsAdmin.uninstallPlugin';
|
||||
|
||||
private $validSortMethods = array('popular', 'newest', 'alpha');
|
||||
private $defaultSortMethod = 'popular';
|
||||
|
||||
private function createUpdateOrInstallView($template, $nonceName)
|
||||
{
|
||||
static::dieIfMarketplaceIsDisabled();
|
||||
|
||||
$pluginName = $this->initPluginModification($nonceName);
|
||||
$this->dieIfPluginsAdminIsDisabled();
|
||||
|
||||
$view = $this->configureView('@CorePluginsAdmin/' . $template);
|
||||
|
||||
$view->plugin = array('name' => $pluginName);
|
||||
|
||||
try {
|
||||
$pluginInstaller = new PluginInstaller($pluginName);
|
||||
$pluginInstaller->installOrUpdatePluginFromMarketplace();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$notification = new Notification($e->getMessage());
|
||||
$notification->context = Notification::CONTEXT_ERROR;
|
||||
Notification\Manager::notify('CorePluginsAdmin_InstallPlugin', $notification);
|
||||
|
||||
$this->redirectAfterModification(true);
|
||||
return;
|
||||
}
|
||||
|
||||
$marketplace = new Marketplace();
|
||||
$view->plugin = $marketplace->getPluginInfo($pluginName);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
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(static::ACTIVATE_NONCE);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function uploadPlugin()
|
||||
{
|
||||
static::dieIfPluginsAdminIsDisabled();
|
||||
Piwik::checkUserHasSuperUserAccess();
|
||||
|
||||
$nonce = Common::getRequestVar('nonce', null, 'string');
|
||||
|
||||
if (!Nonce::verifyNonce(static::INSTALL_NONCE, $nonce)) {
|
||||
throw new \Exception(Piwik::translate('General_ExceptionNonceMismatch'));
|
||||
}
|
||||
|
||||
Nonce::discardNonce(static::INSTALL_NONCE);
|
||||
|
||||
if (empty($_FILES['pluginZip'])) {
|
||||
throw new \Exception('You did not specify a ZIP file.');
|
||||
}
|
||||
|
||||
if (!empty($_FILES['pluginZip']['error'])) {
|
||||
throw new \Exception('Something went wrong during the plugin file upload. Please try again.');
|
||||
}
|
||||
|
||||
$file = $_FILES['pluginZip']['tmp_name'];
|
||||
if (!file_exists($file)) {
|
||||
throw new \Exception('Something went wrong during the plugin file upload. Please try again.');
|
||||
}
|
||||
|
||||
$view = $this->configureView('@CorePluginsAdmin/uploadPlugin');
|
||||
|
||||
$pluginInstaller = new PluginInstaller('uploaded');
|
||||
$pluginMetadata = $pluginInstaller->installOrUpdatePluginFromFile($file);
|
||||
|
||||
$view->nonce = Nonce::getNonce(static::ACTIVATE_NONCE);
|
||||
$view->plugin = array(
|
||||
'name' => $pluginMetadata->name,
|
||||
'version' => $pluginMetadata->version,
|
||||
'isTheme' => !empty($pluginMetadata->theme),
|
||||
'isActivated' => \Piwik\Plugin\Manager::getInstance()->isPluginActivated($pluginMetadata->name)
|
||||
);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function pluginDetails()
|
||||
{
|
||||
static::dieIfMarketplaceIsDisabled();
|
||||
|
||||
$pluginName = Common::getRequestVar('pluginName', null, 'string');
|
||||
$activeTab = Common::getRequestVar('activeTab', '', 'string');
|
||||
if ('changelog' !== $activeTab) {
|
||||
$activeTab = '';
|
||||
}
|
||||
|
||||
$view = $this->configureView('@CorePluginsAdmin/pluginDetails');
|
||||
|
||||
try {
|
||||
$marketplace = new Marketplace();
|
||||
$view->plugin = $marketplace->getPluginInfo($pluginName);
|
||||
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
|
||||
$view->installNonce = Nonce::getNonce(static::INSTALL_NONCE);
|
||||
$view->updateNonce = Nonce::getNonce(static::UPDATE_NONCE);
|
||||
$view->activeTab = $activeTab;
|
||||
} catch (\Exception $e) {
|
||||
$view->errorMessage = $e->getMessage();
|
||||
}
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
private function dieIfMarketplaceIsDisabled()
|
||||
{
|
||||
if (!CorePluginsAdmin::isMarketplaceEnabled()) {
|
||||
throw new \Exception('The Marketplace feature has been disabled.
|
||||
You may enable the Marketplace by changing the config entry "enable_marketplace" to 1.
|
||||
Please contact your Piwik admins with your request so they can assist.');
|
||||
}
|
||||
|
||||
$this->dieIfPluginsAdminIsDisabled();
|
||||
}
|
||||
|
||||
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 createBrowsePluginsOrThemesView($template, $themesOnly)
|
||||
{
|
||||
static::dieIfMarketplaceIsDisabled();
|
||||
|
||||
$query = Common::getRequestVar('query', '', 'string', $_POST);
|
||||
$sort = Common::getRequestVar('sort', $this->defaultSortMethod, 'string');
|
||||
|
||||
if (!in_array($sort, $this->validSortMethods)) {
|
||||
$sort = $this->defaultSortMethod;
|
||||
}
|
||||
|
||||
$view = $this->configureView('@CorePluginsAdmin/' . $template);
|
||||
|
||||
$marketplace = new Marketplace();
|
||||
$view->plugins = $marketplace->searchPlugins($query, $sort, $themesOnly);
|
||||
|
||||
$view->query = $query;
|
||||
$view->sort = $sort;
|
||||
$view->installNonce = Nonce::getNonce(static::INSTALL_NONCE);
|
||||
$view->updateNonce = Nonce::getNonce(static::UPDATE_NONCE);
|
||||
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
public function browsePlugins()
|
||||
{
|
||||
$view = $this->createBrowsePluginsOrThemesView('browsePlugins', $themesOnly = false);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function browseThemes()
|
||||
{
|
||||
$view = $this->createBrowsePluginsOrThemesView('browseThemes', $themesOnly = true);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function extend()
|
||||
{
|
||||
static::dieIfMarketplaceIsDisabled();
|
||||
|
||||
$view = $this->configureView('@CorePluginsAdmin/extend');
|
||||
$view->installNonce = Nonce::getNonce(static::INSTALL_NONCE);
|
||||
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
private function createPluginsOrThemesView($template, $themesOnly)
|
||||
{
|
||||
Piwik::checkUserHasSuperUserAccess();
|
||||
|
||||
$view = $this->configureView('@CorePluginsAdmin/' . $template);
|
||||
|
||||
$view->updateNonce = Nonce::getNonce(static::UPDATE_NONCE);
|
||||
$view->activateNonce = Nonce::getNonce(static::ACTIVATE_NONCE);
|
||||
$view->uninstallNonce = Nonce::getNonce(static::UNINSTALL_NONCE);
|
||||
$view->deactivateNonce = Nonce::getNonce(static::DEACTIVATE_NONCE);
|
||||
$view->pluginsInfo = $this->getPluginsInfo($themesOnly);
|
||||
|
||||
$users = \Piwik\Plugins\UsersManager\API::getInstance()->getUsers();
|
||||
$view->otherUsersCount = count($users) - 1;
|
||||
$view->themeEnabled = \Piwik\Plugin\Manager::getInstance()->getThemeEnabled()->getPluginName();
|
||||
|
||||
$view->pluginNamesHavingSettings = $this->getPluginNamesHavingSettingsForCurrentUser();
|
||||
$view->isMarketplaceEnabled = CorePluginsAdmin::isMarketplaceEnabled();
|
||||
$view->isPluginsAdminEnabled = CorePluginsAdmin::isPluginsAdminEnabled();
|
||||
|
||||
$view->pluginsHavingUpdate = array();
|
||||
$view->marketplacePluginNames = array();
|
||||
|
||||
if (CorePluginsAdmin::isMarketplaceEnabled()) {
|
||||
try {
|
||||
$marketplace = new Marketplace();
|
||||
$view->marketplacePluginNames = $marketplace->getAvailablePluginNames($themesOnly);
|
||||
$view->pluginsHavingUpdate = $marketplace->getPluginsHavingUpdate($themesOnly);
|
||||
} catch(Exception $e) {
|
||||
// curl exec connection error (ie. server not connected to internet)
|
||||
}
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
public function plugins()
|
||||
{
|
||||
$view = $this->createPluginsOrThemesView('plugins', $themesOnly = false);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function themes()
|
||||
{
|
||||
$view = $this->createPluginsOrThemesView('themes', $themesOnly = true);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
protected function configureView($template)
|
||||
{
|
||||
Piwik::checkUserIsNotAnonymous();
|
||||
|
||||
$view = new View($template);
|
||||
$this->setBasicVariablesView($view);
|
||||
|
||||
// If user can manage plugins+themes, display a warning if config not writable
|
||||
if (CorePluginsAdmin::isPluginsAdminEnabled()) {
|
||||
$this->displayWarningIfConfigFileNotWritable();
|
||||
}
|
||||
|
||||
$view->errorMessage = '';
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
protected function getPluginsInfo($themesOnly = false)
|
||||
{
|
||||
$pluginManager = \Piwik\Plugin\Manager::getInstance();
|
||||
$plugins = $pluginManager->returnLoadedPluginsInfo();
|
||||
|
||||
foreach ($plugins as $pluginName => &$plugin) {
|
||||
|
||||
$plugin['isCorePlugin'] = $pluginManager->isPluginBundledWithCore($pluginName);
|
||||
|
||||
if (!isset($plugin['info'])) {
|
||||
|
||||
$suffix = Piwik::translate('CorePluginsAdmin_PluginNotWorkingAlternative');
|
||||
// If the plugin has been renamed, we do not show message to ask user to update plugin
|
||||
if($pluginName != Request::renameModule($pluginName)) {
|
||||
$suffix = "You may uninstall the plugin or manually delete the files in piwik/plugins/$pluginName/";
|
||||
}
|
||||
|
||||
$description = '<strong><em>'
|
||||
. Piwik::translate('CorePluginsAdmin_PluginNotCompatibleWith', array($pluginName, self::getPiwikVersion()))
|
||||
. '</strong><br/>'
|
||||
. $suffix
|
||||
. '</em>';
|
||||
$plugin['info'] = array(
|
||||
'description' => $description,
|
||||
'version' => Piwik::translate('General_Unknown'),
|
||||
'theme' => false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$pluginsFiltered = $this->keepPluginsOrThemes($themesOnly, $plugins);
|
||||
return $pluginsFiltered;
|
||||
}
|
||||
|
||||
protected function keepPluginsOrThemes($themesOnly, $plugins)
|
||||
{
|
||||
$pluginsFiltered = array();
|
||||
foreach ($plugins as $name => $thisPlugin) {
|
||||
|
||||
$isTheme = false;
|
||||
if (!empty($thisPlugin['info']['theme'])) {
|
||||
$isTheme = (bool)$thisPlugin['info']['theme'];
|
||||
}
|
||||
if (($themesOnly && $isTheme)
|
||||
|| (!$themesOnly && !$isTheme)
|
||||
) {
|
||||
$pluginsFiltered[$name] = $thisPlugin;
|
||||
}
|
||||
}
|
||||
return $pluginsFiltered;
|
||||
}
|
||||
|
||||
public function safemode($lastError = array())
|
||||
{
|
||||
if (empty($lastError)) {
|
||||
$lastError = array(
|
||||
'message' => Common::getRequestVar('error_message', null, 'string'),
|
||||
'file' => Common::getRequestVar('error_file', null, 'string'),
|
||||
'line' => Common::getRequestVar('error_line', null, 'integer')
|
||||
);
|
||||
}
|
||||
|
||||
$outputFormat = Common::getRequestVar('format', 'html', 'string');
|
||||
$outputFormat = strtolower($outputFormat);
|
||||
|
||||
if (!empty($outputFormat) && 'html' !== $outputFormat) {
|
||||
|
||||
$errorMessage = $lastError['message'];
|
||||
|
||||
if (Piwik::isUserIsAnonymous()) {
|
||||
$errorMessage = 'A fatal error occurred.';
|
||||
}
|
||||
|
||||
$response = new \Piwik\API\ResponseBuilder($outputFormat);
|
||||
$message = $response->getResponseException(new Exception($errorMessage));
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
if(Common::isPhpCliMode()) {
|
||||
Piwik_ExitWithMessage("Error:" . var_export($lastError, true));
|
||||
}
|
||||
|
||||
$view = new View('@CorePluginsAdmin/safemode');
|
||||
$view->lastError = $lastError;
|
||||
$view->isSuperUser = Piwik::hasUserSuperUserAccess();
|
||||
$view->isAnonymousUser = Piwik::isUserIsAnonymous();
|
||||
$view->plugins = Plugin\Manager::getInstance()->returnLoadedPluginsInfo();
|
||||
$view->deactivateNonce = Nonce::getNonce(static::DEACTIVATE_NONCE);
|
||||
$view->uninstallNonce = Nonce::getNonce(static::UNINSTALL_NONCE);
|
||||
$view->emailSuperUser = implode(',', Piwik::getAllSuperUserAccessEmailAddresses());
|
||||
$view->piwikVersion = Version::VERSION;
|
||||
$view->showVersion = !Common::getRequestVar('tests_hide_piwik_version', 0);
|
||||
$view->pluginCausesIssue = '';
|
||||
|
||||
if (!empty($lastError['file'])) {
|
||||
preg_match('/piwik\/plugins\/(.*)\//', $lastError['file'], $matches);
|
||||
|
||||
if (!empty($matches[1])) {
|
||||
$view->pluginCausesIssue = $matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function activate($redirectAfter = true)
|
||||
{
|
||||
$pluginName = $this->initPluginModification(static::ACTIVATE_NONCE);
|
||||
$this->dieIfPluginsAdminIsDisabled();
|
||||
|
||||
\Piwik\Plugin\Manager::getInstance()->activatePlugin($pluginName);
|
||||
|
||||
if ($redirectAfter) {
|
||||
$plugin = \Piwik\Plugin\Manager::getInstance()->loadPlugin($pluginName);
|
||||
|
||||
$actionToRedirect = 'plugins';
|
||||
if ($plugin->isTheme()) {
|
||||
$actionToRedirect = 'themes';
|
||||
}
|
||||
|
||||
$message = Piwik::translate('CorePluginsAdmin_SuccessfullyActicated', array($pluginName));
|
||||
if (SettingsManager::hasPluginSettingsForCurrentUser($pluginName)) {
|
||||
$target = sprintf('<a href="index.php%s#%s">',
|
||||
Url::getCurrentQueryStringWithParametersModified(array('module' => 'CoreAdminHome', 'action' => 'pluginSettings')),
|
||||
$pluginName);
|
||||
$message .= ' ' . Piwik::translate('CorePluginsAdmin_ChangeSettingsPossible', array($target, '</a>'));
|
||||
}
|
||||
|
||||
$notification = new Notification($message);
|
||||
$notification->raw = true;
|
||||
$notification->title = Piwik::translate('General_WellDone');
|
||||
$notification->context = Notification::CONTEXT_SUCCESS;
|
||||
Notification\Manager::notify('CorePluginsAdmin_PluginActivated', $notification);
|
||||
|
||||
$this->redirectToIndex('CorePluginsAdmin', $actionToRedirect);
|
||||
}
|
||||
}
|
||||
|
||||
public function deactivate($redirectAfter = true)
|
||||
{
|
||||
$pluginName = $this->initPluginModification(static::DEACTIVATE_NONCE);
|
||||
$this->dieIfPluginsAdminIsDisabled();
|
||||
|
||||
\Piwik\Plugin\Manager::getInstance()->deactivatePlugin($pluginName);
|
||||
$this->redirectAfterModification($redirectAfter);
|
||||
}
|
||||
|
||||
public function uninstall($redirectAfter = true)
|
||||
{
|
||||
$pluginName = $this->initPluginModification(static::UNINSTALL_NONCE);
|
||||
$this->dieIfPluginsAdminIsDisabled();
|
||||
|
||||
$uninstalled = \Piwik\Plugin\Manager::getInstance()->uninstallPlugin($pluginName);
|
||||
|
||||
if (!$uninstalled) {
|
||||
$path = Filesystem::getPathToPiwikRoot() . '/plugins/' . $pluginName . '/';
|
||||
$messagePermissions = Filechecks::getErrorMessageMissingPermissions($path);
|
||||
|
||||
$messageIntro = Piwik::translate("Warning: \"%s\" could not be uninstalled. Piwik did not have enough permission to delete the files in $path. ",
|
||||
$pluginName);
|
||||
$exitMessage = $messageIntro . "<br/><br/>" . $messagePermissions;
|
||||
$exitMessage .= "<br> Or manually delete this directory (using FTP or SSH access)";
|
||||
Piwik_ExitWithMessage($exitMessage, $optionalTrace = false, $optionalLinks = false, $optionalLinkBack = true);
|
||||
}
|
||||
|
||||
$this->redirectAfterModification($redirectAfter);
|
||||
}
|
||||
|
||||
protected function initPluginModification($nonceName)
|
||||
{
|
||||
Piwik::checkUserHasSuperUserAccess();
|
||||
|
||||
$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');
|
||||
|
||||
return $pluginName;
|
||||
}
|
||||
|
||||
protected function redirectAfterModification($redirectAfter)
|
||||
{
|
||||
if ($redirectAfter) {
|
||||
Url::redirectToReferrer();
|
||||
}
|
||||
}
|
||||
|
||||
private function getPluginNamesHavingSettingsForCurrentUser()
|
||||
{
|
||||
return array_keys(SettingsManager::getPluginSettingsForCurrentUser());
|
||||
}
|
||||
|
||||
}
|
||||
137
www/analytics/plugins/CorePluginsAdmin/CorePluginsAdmin.php
Normal file
137
www/analytics/plugins/CorePluginsAdmin/CorePluginsAdmin.php
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
use Piwik\Config;
|
||||
use Piwik\Menu\MenuAdmin;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugin;
|
||||
use Piwik\ScheduledTask;
|
||||
use Piwik\ScheduledTime;
|
||||
use Piwik\Plugin\Manager as PluginManager;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class CorePluginsAdmin extends \Piwik\Plugin
|
||||
{
|
||||
/**
|
||||
* @see Piwik\Plugin::getListHooksRegistered
|
||||
*/
|
||||
public function getListHooksRegistered()
|
||||
{
|
||||
return array(
|
||||
'Menu.Admin.addItems' => 'addMenu',
|
||||
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
|
||||
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
|
||||
'TaskScheduler.getScheduledTasks' => 'getScheduledTasks',
|
||||
'Translate.getClientSideTranslationKeys' => 'getClientSideTranslationKeys'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all scheduled tasks executed by this plugin.
|
||||
*/
|
||||
public function getScheduledTasks(&$tasks)
|
||||
{
|
||||
$tasks[] = new ScheduledTask(
|
||||
'Piwik\Plugins\CorePluginsAdmin\MarketplaceApiClient',
|
||||
'clearAllCacheEntries',
|
||||
null,
|
||||
ScheduledTime::factory('daily'),
|
||||
ScheduledTask::LOWEST_PRIORITY
|
||||
);
|
||||
|
||||
if (self::isMarketplaceEnabled()) {
|
||||
$sendUpdateNotification = new ScheduledTask ($this,
|
||||
'sendNotificationIfUpdatesAvailable',
|
||||
null,
|
||||
ScheduledTime::factory('daily'),
|
||||
ScheduledTask::LOWEST_PRIORITY);
|
||||
$tasks[] = $sendUpdateNotification;
|
||||
}
|
||||
}
|
||||
|
||||
public function sendNotificationIfUpdatesAvailable()
|
||||
{
|
||||
$updateCommunication = new UpdateCommunication();
|
||||
if ($updateCommunication->isEnabled()) {
|
||||
$updateCommunication->sendNotificationIfUpdatesAvailable();
|
||||
}
|
||||
}
|
||||
|
||||
public function getStylesheetFiles(&$stylesheets)
|
||||
{
|
||||
$stylesheets[] = "plugins/CorePluginsAdmin/stylesheets/marketplace.less";
|
||||
$stylesheets[] = "plugins/CorePluginsAdmin/stylesheets/plugins_admin.less";
|
||||
}
|
||||
|
||||
function addMenu()
|
||||
{
|
||||
$pluginsUpdateMessage = '';
|
||||
$themesUpdateMessage = '';
|
||||
|
||||
if (Piwik::hasUserSuperUserAccess() && static::isMarketplaceEnabled()) {
|
||||
$marketplace = new Marketplace();
|
||||
$pluginsHavingUpdate = $marketplace->getPluginsHavingUpdate($themesOnly = false);
|
||||
$themesHavingUpdate = $marketplace->getPluginsHavingUpdate($themesOnly = true);
|
||||
|
||||
if (!empty($pluginsHavingUpdate)) {
|
||||
$pluginsUpdateMessage = sprintf(' (%d)', count($pluginsHavingUpdate));
|
||||
}
|
||||
if (!empty($themesHavingUpdate)) {
|
||||
$themesUpdateMessage = sprintf(' (%d)', count($themesHavingUpdate));
|
||||
}
|
||||
}
|
||||
|
||||
MenuAdmin::getInstance()->add('CorePluginsAdmin_MenuPlatform', null, "", !Piwik::isUserIsAnonymous(), $order = 7);
|
||||
MenuAdmin::getInstance()->add('CorePluginsAdmin_MenuPlatform', Piwik::translate('General_Plugins') . $pluginsUpdateMessage,
|
||||
array('module' => 'CorePluginsAdmin', 'action' => 'plugins', 'activated' => ''),
|
||||
Piwik::hasUserSuperUserAccess(),
|
||||
$order = 1);
|
||||
MenuAdmin::getInstance()->add('CorePluginsAdmin_MenuPlatform', Piwik::translate('CorePluginsAdmin_Themes') . $themesUpdateMessage,
|
||||
array('module' => 'CorePluginsAdmin', 'action' => 'themes', 'activated' => ''),
|
||||
Piwik::hasUserSuperUserAccess(),
|
||||
$order = 3);
|
||||
|
||||
if (static::isMarketplaceEnabled()) {
|
||||
|
||||
MenuAdmin::getInstance()->add('CorePluginsAdmin_MenuPlatform', 'CorePluginsAdmin_Marketplace',
|
||||
array('module' => 'CorePluginsAdmin', 'action' => 'extend', 'activated' => ''),
|
||||
!Piwik::isUserIsAnonymous(),
|
||||
$order = 5);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static function isMarketplaceEnabled()
|
||||
{
|
||||
return (bool) Config::getInstance()->General['enable_marketplace'];
|
||||
}
|
||||
|
||||
public static function isPluginsAdminEnabled()
|
||||
{
|
||||
return (bool) Config::getInstance()->General['enable_plugins_admin'];
|
||||
}
|
||||
|
||||
public function getJsFiles(&$jsFiles)
|
||||
{
|
||||
$jsFiles[] = "plugins/CoreHome/javascripts/popover.js";
|
||||
$jsFiles[] = "plugins/CorePluginsAdmin/javascripts/pluginDetail.js";
|
||||
$jsFiles[] = "plugins/CorePluginsAdmin/javascripts/pluginOverview.js";
|
||||
$jsFiles[] = "plugins/CorePluginsAdmin/javascripts/pluginExtend.js";
|
||||
$jsFiles[] = "plugins/CorePluginsAdmin/javascripts/plugins.js";
|
||||
}
|
||||
|
||||
public function getClientSideTranslationKeys(&$translations)
|
||||
{
|
||||
$translations[] = 'CorePluginsAdmin_NoZipFileSelected';
|
||||
}
|
||||
|
||||
}
|
||||
197
www/analytics/plugins/CorePluginsAdmin/Marketplace.php
Normal file
197
www/analytics/plugins/CorePluginsAdmin/Marketplace.php
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
use Piwik\Date;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugin\Dependency as PluginDependency;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Marketplace
|
||||
{
|
||||
/**
|
||||
* @var MarketplaceApiClient
|
||||
*/
|
||||
private $client;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = new MarketplaceApiClient();
|
||||
}
|
||||
|
||||
public function getPluginInfo($pluginName)
|
||||
{
|
||||
$marketplace = new MarketplaceApiClient();
|
||||
|
||||
$plugin = $marketplace->getPluginInfo($pluginName);
|
||||
$plugin = $this->enrichPluginInformation($plugin);
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
public function getAvailablePluginNames($themesOnly)
|
||||
{
|
||||
if ($themesOnly) {
|
||||
$plugins = $this->client->searchForThemes('', '', '');
|
||||
} else {
|
||||
$plugins = $this->client->searchForPlugins('', '', '');
|
||||
}
|
||||
|
||||
$names = array();
|
||||
foreach ($plugins as $plugin) {
|
||||
$names[] = $plugin['name'];
|
||||
}
|
||||
|
||||
return $names;
|
||||
}
|
||||
|
||||
public function getAllAvailablePluginNames()
|
||||
{
|
||||
return array_merge(
|
||||
$this->getAvailablePluginNames(true),
|
||||
$this->getAvailablePluginNames(false)
|
||||
);
|
||||
}
|
||||
|
||||
public function searchPlugins($query, $sort, $themesOnly)
|
||||
{
|
||||
if ($themesOnly) {
|
||||
$plugins = $this->client->searchForThemes('', $query, $sort);
|
||||
} else {
|
||||
$plugins = $this->client->searchForPlugins('', $query, $sort);
|
||||
}
|
||||
|
||||
foreach ($plugins as $key => $plugin) {
|
||||
$plugins[$key] = $this->enrichPluginInformation($plugin);
|
||||
}
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
private function getPluginUpdateInformation($plugin)
|
||||
{
|
||||
if (empty($plugin['name'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pluginsHavingUpdate = $this->getPluginsHavingUpdate($plugin['isTheme']);
|
||||
|
||||
foreach ($pluginsHavingUpdate as $pluginHavingUpdate) {
|
||||
if ($plugin['name'] == $pluginHavingUpdate['name']) {
|
||||
return $pluginHavingUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function hasPluginUpdate($plugin)
|
||||
{
|
||||
$update = $this->getPluginUpdateInformation($plugin);
|
||||
|
||||
return !empty($update);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $themesOnly
|
||||
* @return array
|
||||
*/
|
||||
public function getPluginsHavingUpdate($themesOnly)
|
||||
{
|
||||
$pluginManager = \Piwik\Plugin\Manager::getInstance();
|
||||
$pluginManager->returnLoadedPluginsInfo();
|
||||
$loadedPlugins = $pluginManager->getLoadedPlugins();
|
||||
|
||||
try {
|
||||
$pluginsHavingUpdate = $this->client->getInfoOfPluginsHavingUpdate($loadedPlugins, $themesOnly);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$pluginsHavingUpdate = array();
|
||||
}
|
||||
|
||||
foreach ($pluginsHavingUpdate as &$updatePlugin) {
|
||||
foreach ($loadedPlugins as $loadedPlugin) {
|
||||
|
||||
if (!empty($updatePlugin['name'])
|
||||
&& $loadedPlugin->getPluginName() == $updatePlugin['name']
|
||||
) {
|
||||
|
||||
$updatePlugin['currentVersion'] = $loadedPlugin->getVersion();
|
||||
$updatePlugin['isActivated'] = $pluginManager->isPluginActivated($updatePlugin['name']);
|
||||
$updatePlugin = $this->addMissingRequirements($updatePlugin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pluginsHavingUpdate;
|
||||
}
|
||||
|
||||
private function enrichPluginInformation($plugin)
|
||||
{
|
||||
$dateFormat = Piwik::translate('CoreHome_ShortDateFormatWithYear');
|
||||
|
||||
$plugin['canBeUpdated'] = $this->hasPluginUpdate($plugin);
|
||||
$plugin['isInstalled'] = \Piwik\Plugin\Manager::getInstance()->isPluginLoaded($plugin['name']);
|
||||
$plugin['lastUpdated'] = Date::factory($plugin['lastUpdated'])->getLocalized($dateFormat);
|
||||
|
||||
if ($plugin['canBeUpdated']) {
|
||||
$pluginUpdate = $this->getPluginUpdateInformation($plugin);
|
||||
$plugin['repositoryChangelogUrl'] = $pluginUpdate['repositoryChangelogUrl'];
|
||||
$plugin['currentVersion'] = $pluginUpdate['currentVersion'];
|
||||
}
|
||||
|
||||
if (!empty($plugin['activity']['lastCommitDate'])
|
||||
&& false === strpos($plugin['activity']['lastCommitDate'], '0000')) {
|
||||
|
||||
$dateFormat = Piwik::translate('CoreHome_DateFormat');
|
||||
$plugin['activity']['lastCommitDate'] = Date::factory($plugin['activity']['lastCommitDate'])->getLocalized($dateFormat);
|
||||
} else {
|
||||
$plugin['activity']['lastCommitDate'] = null;
|
||||
}
|
||||
|
||||
if (!empty($plugin['versions'])) {
|
||||
|
||||
$dateFormat = Piwik::translate('CoreHome_DateFormat');
|
||||
|
||||
foreach ($plugin['versions'] as $index => $version) {
|
||||
$plugin['versions'][$index]['release'] = Date::factory($version['release'])->getLocalized($dateFormat);
|
||||
}
|
||||
}
|
||||
|
||||
$plugin = $this->addMissingRequirements($plugin);
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $plugin
|
||||
*/
|
||||
private function addMissingRequirements($plugin)
|
||||
{
|
||||
$plugin['missingRequirements'] = array();
|
||||
|
||||
if (empty($plugin['versions']) || !is_array($plugin['versions'])) {
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
$latestVersion = $plugin['versions'][count($plugin['versions']) - 1];
|
||||
|
||||
if (empty($latestVersion['requires'])) {
|
||||
return $plugin;
|
||||
}
|
||||
|
||||
$requires = $latestVersion['requires'];
|
||||
|
||||
$dependency = new PluginDependency();
|
||||
$plugin['missingRequirements'] = $dependency->getMissingDependencies($requires);
|
||||
|
||||
return $plugin;
|
||||
}
|
||||
}
|
||||
202
www/analytics/plugins/CorePluginsAdmin/MarketplaceApiClient.php
Normal file
202
www/analytics/plugins/CorePluginsAdmin/MarketplaceApiClient.php
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
use Piwik\CacheFile;
|
||||
use Piwik\Http;
|
||||
use Piwik\Version;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class MarketplaceApiClient
|
||||
{
|
||||
const CACHE_TIMEOUT_IN_SECONDS = 1200;
|
||||
const HTTP_REQUEST_TIMEOUT = 3;
|
||||
|
||||
private $domain = 'http://plugins.piwik.org';
|
||||
|
||||
/**
|
||||
* @var CacheFile
|
||||
*/
|
||||
private $cache = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->cache = new CacheFile('marketplace', self::CACHE_TIMEOUT_IN_SECONDS);
|
||||
}
|
||||
|
||||
public static function clearAllCacheEntries()
|
||||
{
|
||||
$cache = new CacheFile('marketplace');
|
||||
$cache->deleteAll();
|
||||
}
|
||||
|
||||
public function getPluginInfo($name)
|
||||
{
|
||||
$action = sprintf('plugins/%s/info', $name);
|
||||
|
||||
return $this->fetch($action, array());
|
||||
}
|
||||
|
||||
public function download($pluginOrThemeName, $target)
|
||||
{
|
||||
$downloadUrl = $this->getDownloadUrl($pluginOrThemeName);
|
||||
|
||||
if (empty($downloadUrl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$success = Http::fetchRemoteFile($downloadUrl, $target, 0, static::HTTP_REQUEST_TIMEOUT);
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Piwik\Plugin[] $plugins
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function checkUpdates($plugins)
|
||||
{
|
||||
$params = array();
|
||||
|
||||
foreach ($plugins as $plugin) {
|
||||
$pluginName = $plugin->getPluginName();
|
||||
if (!\Piwik\Plugin\Manager::getInstance()->isPluginBundledWithCore($pluginName)) {
|
||||
$params[] = array('name' => $plugin->getPluginName(), 'version' => $plugin->getVersion());
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($params)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$params = array('plugins' => $params);
|
||||
|
||||
$hasUpdates = $this->fetch('plugins/checkUpdates', array('plugins' => json_encode($params)));
|
||||
|
||||
if (empty($hasUpdates)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $hasUpdates;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Piwik\Plugin[] $plugins
|
||||
* @param bool $themesOnly
|
||||
* @return array
|
||||
*/
|
||||
public function getInfoOfPluginsHavingUpdate($plugins, $themesOnly)
|
||||
{
|
||||
$hasUpdates = $this->checkUpdates($plugins);
|
||||
|
||||
$pluginDetails = array();
|
||||
|
||||
foreach ($hasUpdates as $pluginHavingUpdate) {
|
||||
$plugin = $this->getPluginInfo($pluginHavingUpdate['name']);
|
||||
$plugin['repositoryChangelogUrl'] = $pluginHavingUpdate['repositoryChangelogUrl'];
|
||||
|
||||
if (!empty($plugin['isTheme']) == $themesOnly) {
|
||||
$pluginDetails[] = $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
return $pluginDetails;
|
||||
}
|
||||
|
||||
public function searchForPlugins($keywords, $query, $sort)
|
||||
{
|
||||
$response = $this->fetch('plugins', array('keywords' => $keywords, 'query' => $query, 'sort' => $sort));
|
||||
|
||||
if (!empty($response['plugins'])) {
|
||||
return $response['plugins'];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function searchForThemes($keywords, $query, $sort)
|
||||
{
|
||||
$response = $this->fetch('themes', array('keywords' => $keywords, 'query' => $query, 'sort' => $sort));
|
||||
|
||||
if (!empty($response['plugins'])) {
|
||||
return $response['plugins'];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
private function fetch($action, $params)
|
||||
{
|
||||
ksort($params);
|
||||
$query = http_build_query($params);
|
||||
$result = $this->getCachedResult($action, $query);
|
||||
|
||||
if (false === $result) {
|
||||
$endpoint = $this->domain . '/api/1.0/';
|
||||
$url = sprintf('%s%s?%s', $endpoint, $action, $query);
|
||||
$response = Http::sendHttpRequest($url, static::HTTP_REQUEST_TIMEOUT);
|
||||
$result = json_decode($response, true);
|
||||
|
||||
if (is_null($result)) {
|
||||
$message = sprintf('There was an error reading the response from the Marketplace: %s. Please try again later.',
|
||||
substr($response, 0, 50));
|
||||
throw new MarketplaceApiException($message);
|
||||
}
|
||||
|
||||
if (!empty($result['error'])) {
|
||||
throw new MarketplaceApiException($result['error']);
|
||||
}
|
||||
|
||||
$this->cacheResult($action, $query, $result);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getCachedResult($action, $query)
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($action, $query);
|
||||
|
||||
return $this->cache->get($cacheKey);
|
||||
}
|
||||
|
||||
private function cacheResult($action, $query, $result)
|
||||
{
|
||||
$cacheKey = $this->getCacheKey($action, $query);
|
||||
|
||||
$this->cache->set($cacheKey, $result);
|
||||
}
|
||||
|
||||
private function getCacheKey($action, $query)
|
||||
{
|
||||
return sprintf('api.1.0.%s.%s', str_replace('/', '.', $action), md5($query));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pluginOrThemeName
|
||||
* @throws MarketplaceApiException
|
||||
* @return string
|
||||
*/
|
||||
public function getDownloadUrl($pluginOrThemeName)
|
||||
{
|
||||
$plugin = $this->getPluginInfo($pluginOrThemeName);
|
||||
|
||||
if (empty($plugin['versions'])) {
|
||||
throw new MarketplaceApiException('Plugin has no versions.');
|
||||
}
|
||||
|
||||
$latestVersion = array_pop($plugin['versions']);
|
||||
$downloadUrl = $latestVersion['download'];
|
||||
|
||||
return $this->domain . $downloadUrl . '?coreVersion=' . Version::VERSION;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
/**
|
||||
*/
|
||||
class MarketplaceApiException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
294
www/analytics/plugins/CorePluginsAdmin/PluginInstaller.php
Normal file
294
www/analytics/plugins/CorePluginsAdmin/PluginInstaller.php
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
use Piwik\Filechecks;
|
||||
use Piwik\Filesystem;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\SettingsPiwik;
|
||||
use Piwik\Unzip;
|
||||
use Piwik\Plugin\Dependency as PluginDependency;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class PluginInstaller
|
||||
{
|
||||
const PATH_TO_DOWNLOAD = '/tmp/latest/plugins/';
|
||||
const PATH_TO_EXTRACT = '/plugins/';
|
||||
|
||||
private $pluginName;
|
||||
|
||||
public function __construct($pluginName)
|
||||
{
|
||||
$this->pluginName = $pluginName;
|
||||
}
|
||||
|
||||
public function installOrUpdatePluginFromMarketplace()
|
||||
{
|
||||
$tmpPluginZip = PIWIK_USER_PATH . self::PATH_TO_DOWNLOAD . $this->pluginName . '.zip';
|
||||
$tmpPluginFolder = PIWIK_USER_PATH . self::PATH_TO_DOWNLOAD . $this->pluginName;
|
||||
|
||||
$tmpPluginZip = SettingsPiwik::rewriteTmpPathWithHostname($tmpPluginZip);
|
||||
$tmpPluginFolder = SettingsPiwik::rewriteTmpPathWithHostname($tmpPluginFolder);
|
||||
|
||||
try {
|
||||
$this->makeSureFoldersAreWritable();
|
||||
$this->makeSurePluginNameIsValid();
|
||||
$this->downloadPluginFromMarketplace($tmpPluginZip);
|
||||
$this->extractPluginFiles($tmpPluginZip, $tmpPluginFolder);
|
||||
$this->makeSurePluginJsonExists($tmpPluginFolder);
|
||||
$metadata = $this->getPluginMetadataIfValid($tmpPluginFolder);
|
||||
$this->makeSureThereAreNoMissingRequirements($metadata);
|
||||
$this->copyPluginToDestination($tmpPluginFolder);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->removeFileIfExists($tmpPluginZip);
|
||||
$this->removeFolderIfExists($tmpPluginFolder);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->removeFileIfExists($tmpPluginZip);
|
||||
$this->removeFolderIfExists($tmpPluginFolder);
|
||||
}
|
||||
|
||||
public function installOrUpdatePluginFromFile($pathToZip)
|
||||
{
|
||||
$tmpPluginFolder = PIWIK_USER_PATH . self::PATH_TO_DOWNLOAD . $this->pluginName;
|
||||
$tmpPluginFolder = SettingsPiwik::rewriteTmpPathWithHostname($tmpPluginFolder);
|
||||
|
||||
try {
|
||||
$this->makeSureFoldersAreWritable();
|
||||
$this->extractPluginFiles($pathToZip, $tmpPluginFolder);
|
||||
|
||||
$this->makeSurePluginJsonExists($tmpPluginFolder);
|
||||
$metadata = $this->getPluginMetadataIfValid($tmpPluginFolder);
|
||||
$this->makeSureThereAreNoMissingRequirements($metadata);
|
||||
|
||||
$this->pluginName = $metadata->name;
|
||||
|
||||
$this->fixPluginFolderIfNeeded($tmpPluginFolder);
|
||||
$this->copyPluginToDestination($tmpPluginFolder);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
||||
$this->removeFileIfExists($pathToZip);
|
||||
$this->removeFolderIfExists($tmpPluginFolder);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$this->removeFileIfExists($pathToZip);
|
||||
$this->removeFolderIfExists($tmpPluginFolder);
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
private function makeSureFoldersAreWritable()
|
||||
{
|
||||
Filechecks::dieIfDirectoriesNotWritable(array(self::PATH_TO_DOWNLOAD, self::PATH_TO_EXTRACT));
|
||||
}
|
||||
|
||||
private function downloadPluginFromMarketplace($pluginZipTargetFile)
|
||||
{
|
||||
$this->removeFileIfExists($pluginZipTargetFile);
|
||||
|
||||
$marketplace = new MarketplaceApiClient();
|
||||
|
||||
try {
|
||||
$marketplace->download($this->pluginName, $pluginZipTargetFile);
|
||||
} catch (\Exception $e) {
|
||||
|
||||
try {
|
||||
$downloadUrl = $marketplace->getDownloadUrl($this->pluginName);
|
||||
$errorMessage = sprintf('Failed to download plugin from %s: %s', $downloadUrl, $e->getMessage());
|
||||
|
||||
} catch (\Exception $ex) {
|
||||
$errorMessage = sprintf('Failed to download plugin: %s', $e->getMessage());
|
||||
}
|
||||
|
||||
throw new PluginInstallerException($errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pluginZipFile
|
||||
* @param $pathExtracted
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function extractPluginFiles($pluginZipFile, $pathExtracted)
|
||||
{
|
||||
$archive = Unzip::factory('PclZip', $pluginZipFile);
|
||||
|
||||
$this->removeFolderIfExists($pathExtracted);
|
||||
|
||||
if (0 == ($pluginFiles = $archive->extract($pathExtracted))) {
|
||||
throw new PluginInstallerException(Piwik::translate('CoreUpdater_ExceptionArchiveIncompatible', $archive->errorInfo()));
|
||||
}
|
||||
|
||||
if (0 == count($pluginFiles)) {
|
||||
throw new PluginInstallerException(Piwik::translate('Plugin Zip File Is Empty'));
|
||||
}
|
||||
}
|
||||
|
||||
private function makeSurePluginJsonExists($tmpPluginFolder)
|
||||
{
|
||||
$pluginJsonPath = $this->getPathToPluginJson($tmpPluginFolder);
|
||||
|
||||
if (!file_exists($pluginJsonPath)) {
|
||||
throw new PluginInstallerException('Plugin is not valid, it is missing the plugin.json file.');
|
||||
}
|
||||
}
|
||||
|
||||
private function makeSureThereAreNoMissingRequirements($metadata)
|
||||
{
|
||||
$requires = array();
|
||||
if(!empty($metadata->require)) {
|
||||
$requires = (array) $metadata->require;
|
||||
}
|
||||
|
||||
$dependency = new PluginDependency();
|
||||
$missingDependencies = $dependency->getMissingDependencies($requires);
|
||||
|
||||
if (!empty($missingDependencies)) {
|
||||
$message = '';
|
||||
foreach ($missingDependencies as $dep) {
|
||||
$params = array(ucfirst($dep['requirement']), $dep['actualVersion'], $dep['requiredVersion']);
|
||||
$message .= Piwik::translate('CorePluginsAdmin_MissingRequirementsNotice', $params);
|
||||
}
|
||||
|
||||
throw new PluginInstallerException($message);
|
||||
}
|
||||
}
|
||||
|
||||
private function getPluginMetadataIfValid($tmpPluginFolder)
|
||||
{
|
||||
$pluginJsonPath = $this->getPathToPluginJson($tmpPluginFolder);
|
||||
|
||||
$metadata = file_get_contents($pluginJsonPath);
|
||||
$metadata = json_decode($metadata);
|
||||
|
||||
if (empty($metadata)) {
|
||||
throw new PluginInstallerException('Plugin is not valid, plugin.json is empty or does not contain valid JSON.');
|
||||
}
|
||||
|
||||
if (empty($metadata->name)) {
|
||||
throw new PluginInstallerException('Plugin is not valid, the plugin.json file does not specify the plugin name.');
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $metadata->name)) {
|
||||
throw new PluginInstallerException('The plugin name specified in plugin.json contains illegal characters. ' .
|
||||
'Plugin name can only contain following characters: [a-zA-Z0-9-_].');
|
||||
}
|
||||
|
||||
if (empty($metadata->version)) {
|
||||
throw new PluginInstallerException('Plugin is not valid, the plugin.json file does not specify the plugin version.');
|
||||
}
|
||||
|
||||
if (empty($metadata->description)) {
|
||||
throw new PluginInstallerException('Plugin is not valid, the plugin.json file does not specify a description.');
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
|
||||
private function getPathToPluginJson($tmpPluginFolder)
|
||||
{
|
||||
$firstSubFolder = $this->getNameOfFirstSubfolder($tmpPluginFolder);
|
||||
$path = $tmpPluginFolder . DIRECTORY_SEPARATOR . $firstSubFolder . DIRECTORY_SEPARATOR . 'plugin.json';
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pluginDir
|
||||
* @throws PluginInstallerException
|
||||
* @return string
|
||||
*/
|
||||
private function getNameOfFirstSubfolder($pluginDir)
|
||||
{
|
||||
if (!($dir = opendir($pluginDir))) {
|
||||
return false;
|
||||
}
|
||||
$firstSubFolder = '';
|
||||
|
||||
while ($file = readdir($dir)) {
|
||||
if ($file[0] != '.' && is_dir($pluginDir . DIRECTORY_SEPARATOR . $file)) {
|
||||
$firstSubFolder = $file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($firstSubFolder)) {
|
||||
throw new PluginInstallerException('The plugin ZIP file does not contain a subfolder, but Piwik expects plugin files to be within a subfolder in the Zip archive.');
|
||||
}
|
||||
|
||||
return $firstSubFolder;
|
||||
}
|
||||
|
||||
private function fixPluginFolderIfNeeded($tmpPluginFolder)
|
||||
{
|
||||
$firstSubFolder = $this->getNameOfFirstSubfolder($tmpPluginFolder);
|
||||
|
||||
if ($firstSubFolder === $this->pluginName) {
|
||||
return;
|
||||
}
|
||||
|
||||
$from = $tmpPluginFolder . DIRECTORY_SEPARATOR . $firstSubFolder;
|
||||
$to = $tmpPluginFolder . DIRECTORY_SEPARATOR . $this->pluginName;
|
||||
rename($from, $to);
|
||||
}
|
||||
|
||||
private function copyPluginToDestination($tmpPluginFolder)
|
||||
{
|
||||
$pluginTargetPath = PIWIK_USER_PATH . self::PATH_TO_EXTRACT . $this->pluginName;
|
||||
|
||||
$this->removeFolderIfExists($pluginTargetPath);
|
||||
|
||||
Filesystem::copyRecursive($tmpPluginFolder, PIWIK_USER_PATH . self::PATH_TO_EXTRACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $pathExtracted
|
||||
*/
|
||||
private function removeFolderIfExists($pathExtracted)
|
||||
{
|
||||
Filesystem::unlinkRecursive($pathExtracted, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $targetTmpFile
|
||||
*/
|
||||
private function removeFileIfExists($targetTmpFile)
|
||||
{
|
||||
if (file_exists($targetTmpFile)) {
|
||||
unlink($targetTmpFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PluginInstallerException
|
||||
*/
|
||||
private function makeSurePluginNameIsValid()
|
||||
{
|
||||
try {
|
||||
$marketplace = new MarketplaceApiClient();
|
||||
$pluginDetails = $marketplace->getPluginInfo($this->pluginName);
|
||||
} catch (\Exception $e) {
|
||||
throw new PluginInstallerException($e->getMessage());
|
||||
}
|
||||
|
||||
if (empty($pluginDetails)) {
|
||||
throw new PluginInstallerException('This plugin was not found in the Marketplace.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
/**
|
||||
* PluginInstallerException
|
||||
*/
|
||||
class PluginInstallerException extends \Exception
|
||||
{
|
||||
|
||||
}
|
||||
210
www/analytics/plugins/CorePluginsAdmin/UpdateCommunication.php
Normal file
210
www/analytics/plugins/CorePluginsAdmin/UpdateCommunication.php
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\CorePluginsAdmin;
|
||||
|
||||
use Piwik\Config;
|
||||
use Piwik\Mail;
|
||||
use Piwik\Option;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\UsersManager\API as UsersManagerApi;
|
||||
use Piwik\SettingsPiwik;
|
||||
|
||||
/**
|
||||
* Class to check and notify users via email if there are plugin updates available.
|
||||
*/
|
||||
class UpdateCommunication
|
||||
{
|
||||
private $enabledOptionName = 'enableUpdateCommunicationPlugins';
|
||||
|
||||
/**
|
||||
* Checks whether plugin update notification is enabled or not. If the marketplace is disabled or if update
|
||||
* communication is disabled in general, it will return false as well.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
if (!$this->canBeEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$isEnabled = Option::get($this->enabledOptionName);
|
||||
|
||||
return !empty($isEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a plugin update notification can be enabled or not. It cannot be enabled if for instance the
|
||||
* Marketplace is disabled or if update notifications are disabled in general.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function canBeEnabled()
|
||||
{
|
||||
$isEnabled = Config::getInstance()->General['enable_update_communication'];
|
||||
|
||||
return CorePluginsAdmin::isMarketplaceEnabled() && !empty($isEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable plugin update notifications.
|
||||
*/
|
||||
public function enable()
|
||||
{
|
||||
Option::set($this->enabledOptionName, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable plugin update notifications.
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
Option::set($this->enabledOptionName, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email to all super users if there is an update available for any plugins from the Marketplace.
|
||||
* For each update we send an email only once.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function sendNotificationIfUpdatesAvailable()
|
||||
{
|
||||
$pluginsHavingUpdate = $this->getPluginsHavingUpdate();
|
||||
|
||||
if (empty($pluginsHavingUpdate)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pluginsToBeNotified = array();
|
||||
|
||||
foreach ($pluginsHavingUpdate as $plugin) {
|
||||
if ($this->hasNotificationAlreadyReceived($plugin)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->setHasLatestUpdateNotificationReceived($plugin);
|
||||
|
||||
$pluginsToBeNotified[] = $plugin;
|
||||
}
|
||||
|
||||
if (!empty($pluginsToBeNotified)) {
|
||||
$this->sendNotifications($pluginsToBeNotified);
|
||||
}
|
||||
}
|
||||
|
||||
protected function sendNotifications($pluginsToBeNotified)
|
||||
{
|
||||
$hasThemeUpdate = false;
|
||||
$hasPluginUpdate = false;
|
||||
|
||||
foreach ($pluginsToBeNotified as $plugin) {
|
||||
$hasThemeUpdate = $hasThemeUpdate || $plugin['isTheme'];
|
||||
$hasPluginUpdate = $hasPluginUpdate || !$plugin['isTheme'];
|
||||
}
|
||||
|
||||
$subject = Piwik::translate('CoreUpdater_NotificationSubjectAvailablePluginUpdate');
|
||||
$message = Piwik::translate('ScheduledReports_EmailHello');
|
||||
$message .= "\n\n";
|
||||
$message .= Piwik::translate('CoreUpdater_ThereIsNewPluginVersionAvailableForUpdate');
|
||||
$message .= "\n\n";
|
||||
|
||||
foreach ($pluginsToBeNotified as $plugin) {
|
||||
$message .= sprintf(' * %s %s', $plugin['name'], $plugin['latestVersion']);
|
||||
$message .= "\n";
|
||||
}
|
||||
|
||||
$message .= "\n";
|
||||
|
||||
$host = SettingsPiwik::getPiwikUrl();
|
||||
if ($hasThemeUpdate) {
|
||||
$message .= Piwik::translate('CoreUpdater_NotificationClickToUpdateThemes') . "\n";
|
||||
$message .= $host. 'index.php?module=CorePluginsAdmin&action=themes';
|
||||
}
|
||||
if ($hasPluginUpdate) {
|
||||
if ($hasThemeUpdate) {
|
||||
$message .= "\n\n";
|
||||
}
|
||||
$message .= Piwik::translate('CoreUpdater_NotificationClickToUpdatePlugins') . "\n";
|
||||
$message .= $host. 'index.php?module=CorePluginsAdmin&action=plugins';
|
||||
}
|
||||
|
||||
$message .= "\n\n";
|
||||
$message .= Piwik::translate('Installation_HappyAnalysing');
|
||||
|
||||
$this->sendEmailNotification($subject, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email notification to all super users.
|
||||
*
|
||||
* @param $subject
|
||||
* @param $message
|
||||
*/
|
||||
protected function sendEmailNotification($subject, $message)
|
||||
{
|
||||
$superUsers = UsersManagerApi::getInstance()->getUsersHavingSuperUserAccess();
|
||||
|
||||
foreach ($superUsers as $superUser) {
|
||||
$mail = new Mail();
|
||||
$mail->setDefaultFromPiwik();
|
||||
$mail->addTo($superUser['email']);
|
||||
$mail->setSubject($subject);
|
||||
$mail->setBodyText($message);
|
||||
$mail->send();
|
||||
}
|
||||
}
|
||||
|
||||
private function setHasLatestUpdateNotificationReceived($plugin)
|
||||
{
|
||||
$latestVersion = $this->getLatestVersion($plugin);
|
||||
|
||||
Option::set($this->getNotificationSentOptionName($plugin), $latestVersion);
|
||||
}
|
||||
|
||||
private function getLatestVersionSent($plugin)
|
||||
{
|
||||
return Option::get($this->getNotificationSentOptionName($plugin));
|
||||
}
|
||||
|
||||
private function getLatestVersion($plugin)
|
||||
{
|
||||
return $plugin['latestVersion'];
|
||||
}
|
||||
|
||||
private function hasNotificationAlreadyReceived($plugin)
|
||||
{
|
||||
$latestVersion = $this->getLatestVersion($plugin);
|
||||
$lastVersionSent = $this->getLatestVersionSent($plugin);
|
||||
|
||||
if (!empty($lastVersionSent)
|
||||
&& ($latestVersion == $lastVersionSent
|
||||
|| version_compare($latestVersion, $lastVersionSent) == -1)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getNotificationSentOptionName($plugin)
|
||||
{
|
||||
return 'last_update_communication_sent_plugin_' . $plugin['name'];
|
||||
}
|
||||
|
||||
protected function getPluginsHavingUpdate()
|
||||
{
|
||||
$marketplace = new Marketplace();
|
||||
$pluginsHavingUpdate = $marketplace->getPluginsHavingUpdate($themesOnly = false);
|
||||
$themesHavingUpdate = $marketplace->getPluginsHavingUpdate($themesOnly = true);
|
||||
|
||||
$plugins = array_merge($pluginsHavingUpdate, $themesHavingUpdate);
|
||||
|
||||
return $plugins;
|
||||
}
|
||||
}
|
||||
BIN
www/analytics/plugins/CorePluginsAdmin/images/plugins.png
Normal file
BIN
www/analytics/plugins/CorePluginsAdmin/images/plugins.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
www/analytics/plugins/CorePluginsAdmin/images/rating_important.png
Executable file
BIN
www/analytics/plugins/CorePluginsAdmin/images/rating_important.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 673 B |
BIN
www/analytics/plugins/CorePluginsAdmin/images/themes.png
Normal file
BIN
www/analytics/plugins/CorePluginsAdmin/images/themes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
88
www/analytics/plugins/CorePluginsAdmin/javascripts/pluginDetail.js
Executable file
88
www/analytics/plugins/CorePluginsAdmin/javascripts/pluginDetail.js
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
function syncMaxHeight (selector) {
|
||||
|
||||
if (!selector) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $nodes = $(selector);
|
||||
|
||||
if (!$nodes) {
|
||||
return;
|
||||
}
|
||||
|
||||
var max = {};
|
||||
$nodes.each(function (index, node) {
|
||||
var $node = $(node);
|
||||
var top = $node.position().top;
|
||||
|
||||
var height = $node.height();
|
||||
|
||||
if (!max[top]) {
|
||||
max[top] = height;
|
||||
} else if (max[top] < height) {
|
||||
max[top] = height;
|
||||
} else {
|
||||
$node.height(max[top] + 'px');
|
||||
}
|
||||
});
|
||||
|
||||
$nodes.each(function (index, node) {
|
||||
var $node = $(node);
|
||||
var top = $node.position().top;
|
||||
|
||||
$node.height(max[top] + 'px');
|
||||
});
|
||||
}
|
||||
|
||||
syncMaxHeight('.pluginslist .plugin');
|
||||
syncMaxHeight('.themeslist .plugin');
|
||||
|
||||
$('.pluginslist, #plugins, .themeslist').on('click', '[data-pluginName]', function (event) {
|
||||
if ($(event.target).hasClass('install') || $(event.target).hasClass('uninstall')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pluginName = $(this).attr('data-pluginName');
|
||||
|
||||
if (!pluginName) {
|
||||
return;
|
||||
}
|
||||
|
||||
var activeTab = $(event.target).attr('data-activePluginTab');
|
||||
if (activeTab) {
|
||||
pluginName += '!' + activeTab;
|
||||
}
|
||||
|
||||
broadcast.propagateNewPopoverParameter('browsePluginDetail', pluginName);
|
||||
});
|
||||
|
||||
var showPopover = function (value) {
|
||||
var pluginName = value;
|
||||
var activeTab = null;
|
||||
|
||||
if (-1 !== value.indexOf('!')) {
|
||||
activeTab = value.substr(value.indexOf('!') + 1);
|
||||
pluginName = value.substr(0, value.indexOf('!'));
|
||||
}
|
||||
|
||||
var url = 'module=CorePluginsAdmin&action=pluginDetails&pluginName=' + encodeURIComponent(pluginName);
|
||||
|
||||
if (activeTab) {
|
||||
url += '&activeTab=' + encodeURIComponent(activeTab);
|
||||
}
|
||||
|
||||
Piwik_Popover.createPopupAndLoadUrl(url, 'details');
|
||||
};
|
||||
|
||||
broadcast.addPopoverHandler('browsePluginDetail', showPopover);
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('.extendPlatform .uploadPlugin').click(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
piwikHelper.modalConfirm('#installPluginByUpload', {
|
||||
yes: function () {
|
||||
window.location = link;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#uploadPluginForm').submit(function (event) {
|
||||
|
||||
var $zipFile = $('[name=pluginZip]');
|
||||
var fileName = $zipFile.val();
|
||||
|
||||
if (!fileName || '.zip' != fileName.slice(-4)) {
|
||||
event.preventDefault();
|
||||
alert(_pk_translate('CorePluginsAdmin_NoZipFileSelected'));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
var uninstallConfirmMessage = '';
|
||||
|
||||
$('#plugins .uninstall').click(function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
var link = $(this).attr('href');
|
||||
var pluginName = $(this).attr('data-pluginName');
|
||||
|
||||
if (!link || !pluginName) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uninstallConfirmMessage) {
|
||||
uninstallConfirmMessage = $('#uninstallPluginConfirm').text();
|
||||
}
|
||||
|
||||
var messageToDisplay = uninstallConfirmMessage.replace('%s', pluginName);
|
||||
|
||||
$('#uninstallPluginConfirm').text(messageToDisplay);
|
||||
|
||||
piwikHelper.modalConfirm('#confirmUninstallPlugin', {
|
||||
yes: function () {
|
||||
window.location = link;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*!
|
||||
* Piwik - Web Analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*/
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
updateAllNumbersOfMatchingPluginsInFilter();
|
||||
|
||||
function filterPlugins()
|
||||
{
|
||||
var filterOrigin = getCurrentFilterOrigin();
|
||||
var filterStatus = getCurrentFilterStatus();
|
||||
|
||||
var $nodesToEnable = getMatchingNodes(filterOrigin, filterStatus);
|
||||
|
||||
$('#plugins tr[data-filter-origin][data-filter-status]').css('display', 'none');
|
||||
$nodesToEnable.css('display', 'table-row');
|
||||
|
||||
updateAllNumbersOfMatchingPluginsInFilter();
|
||||
}
|
||||
|
||||
function updateAllNumbersOfMatchingPluginsInFilter()
|
||||
{
|
||||
var filterOrigin = getCurrentFilterOrigin();
|
||||
var filterStatus = getCurrentFilterStatus();
|
||||
|
||||
updateNumberOfMatchingPluginsInFilter('[data-filter-status="all"]', filterOrigin, 'all');
|
||||
updateNumberOfMatchingPluginsInFilter('[data-filter-status="active"]', filterOrigin, 'active');
|
||||
updateNumberOfMatchingPluginsInFilter('[data-filter-status="inactive"]', filterOrigin, 'inactive');
|
||||
|
||||
updateNumberOfMatchingPluginsInFilter('[data-filter-origin="all"]', 'all', filterStatus);
|
||||
updateNumberOfMatchingPluginsInFilter('[data-filter-origin="core"]', 'core', filterStatus);
|
||||
updateNumberOfMatchingPluginsInFilter('[data-filter-origin="noncore"]', 'noncore', filterStatus);
|
||||
}
|
||||
|
||||
function updateNumberOfMatchingPluginsInFilter(selectorFilterToUpdate, filterOrigin, filterStatus)
|
||||
{
|
||||
var numMatchingNodes = getMatchingNodes(filterOrigin, filterStatus).length;
|
||||
var updatedCounterText = ' (' + numMatchingNodes + ')';
|
||||
|
||||
$('.pluginsFilter ' + selectorFilterToUpdate + ' .counter').text(updatedCounterText);
|
||||
}
|
||||
|
||||
function getCurrentFilterOrigin()
|
||||
{
|
||||
return $('.pluginsFilter .origin a.active').data('filter-origin');
|
||||
}
|
||||
|
||||
function getCurrentFilterStatus()
|
||||
{
|
||||
return $('.pluginsFilter .status a.active').data('filter-status');
|
||||
}
|
||||
|
||||
function getMatchingNodes(filterOrigin, filterStatus)
|
||||
{
|
||||
var query = '#plugins tr';
|
||||
|
||||
if ('all' == filterOrigin) {
|
||||
query += '[data-filter-origin]';
|
||||
} else {
|
||||
query += '[data-filter-origin=' + filterOrigin + ']';
|
||||
}
|
||||
|
||||
if ('all' == filterStatus) {
|
||||
query += '[data-filter-status]';
|
||||
} else {
|
||||
query += '[data-filter-status=' + filterStatus + ']';
|
||||
}
|
||||
|
||||
return $(query);
|
||||
}
|
||||
|
||||
$('.pluginsFilter .status').on('click', 'a', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
$(this).siblings().removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
filterPlugins();
|
||||
});
|
||||
|
||||
$('.pluginsFilter .origin').on('click', 'a', function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
$(this).siblings().removeClass('active');
|
||||
$(this).addClass('active');
|
||||
|
||||
filterPlugins();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,367 @@
|
|||
.extendPlatform {
|
||||
min-width: 580px;
|
||||
|
||||
.introduction { max-width:980px; }
|
||||
.byPlugins { width:50%;float:left; }
|
||||
.byThemes { width:50%;float:left; }
|
||||
.teaserImage { width: 128px; height: 128px; margin: 64px; }
|
||||
.header { font-size: 1.6em; }
|
||||
.callToAction { font-size: 1.1em;line-height: 2em; }
|
||||
}
|
||||
|
||||
#plugins {
|
||||
|
||||
.desc .missingRequirementsNotice {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.plugin-desc-missingrequirements {
|
||||
font-weight:bold;
|
||||
font-style: italic;
|
||||
a {
|
||||
text-decoration: underline !important;
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.settingsLink {
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
|
||||
.admin .pluginsFilter {
|
||||
color: #666;
|
||||
.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #255792;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a .counter {
|
||||
color: #999999;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.getNewPlugins {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
#installPluginByUpload {
|
||||
.description {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.startUpload {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.pluginslist {
|
||||
margin-top: 20px;
|
||||
max-width: 980px;
|
||||
clear: right;
|
||||
|
||||
.plugin {
|
||||
width: 280px;
|
||||
float: left;
|
||||
border: 1px solid #dadada;
|
||||
padding: 15px;
|
||||
background-color: #F6F5F3;
|
||||
margin-right: 14px;
|
||||
margin-bottom: 15px;
|
||||
position: relative;
|
||||
|
||||
.missingRequirementsNotice,
|
||||
.updateAvailableNotice {
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
color: #9b7a44;
|
||||
display: inline-block;
|
||||
background-color: #ffffe0;
|
||||
border-radius: 3px;
|
||||
margin-top: 1px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
a {
|
||||
color: #9b7a44;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #EFEEEC;
|
||||
}
|
||||
|
||||
li {
|
||||
display: inline-block;
|
||||
padding-right: 50px;
|
||||
font-size: 90%;
|
||||
|
||||
&.even {
|
||||
padding-right: 0px;
|
||||
width: 140px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&.odd {
|
||||
padding-right: 0px;
|
||||
width: 130px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.install {
|
||||
float: right;
|
||||
}
|
||||
.update {
|
||||
.install
|
||||
}
|
||||
.more {
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: #255792;
|
||||
}
|
||||
.content {
|
||||
margin-bottom: 46px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.featuredIcon {
|
||||
margin-right: 3px;
|
||||
margin-bottom: 3px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
margin-top: -22px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.metadataSeparator {
|
||||
background-color: lightgray;
|
||||
color: #333;
|
||||
border: 0px;
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
}
|
||||
.metadata {
|
||||
margin-top: 10px;
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&.themes .plugin {
|
||||
.header {
|
||||
display: inline;
|
||||
}
|
||||
.content {
|
||||
margin-bottom: 57px;
|
||||
}
|
||||
.preview {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
}
|
||||
.footer {
|
||||
height: 55px;
|
||||
position: absolute;
|
||||
bottom: 7px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pluginslistNonSuperUserHint {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.pluginslistActionBar {
|
||||
min-width: 650px;
|
||||
max-width: 980px;
|
||||
|
||||
form {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.sort {
|
||||
.active {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.infoBox {
|
||||
margin: 0px 0px 20px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.pluginDetails {
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
line-height: 20px;
|
||||
|
||||
h3, h4, h5, h6 {
|
||||
margin: 20px 0px 10px 0px;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.ui-tabs-panel ul, .ui-tabs-panel ol {
|
||||
list-style: initial;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.content .missingRequirementsNotice,
|
||||
.content .updateAvailableNotice {
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
color: #9b7a44;
|
||||
display: inline-block;
|
||||
background-color: #ffffe0;
|
||||
border-radius: 3px;
|
||||
|
||||
a {
|
||||
color: #9b7a44;
|
||||
font-weight: bold;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
p, .ui-tabs-panel ul, .ui-tabs-panel li {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
text-align: left;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.header .intro {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.description {
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.ui-tabs {
|
||||
padding: 0em;
|
||||
}
|
||||
|
||||
.ui-tabs .ui-tabs-nav {
|
||||
padding: 0em;
|
||||
border-bottom: 1px solid #cccccc;
|
||||
margin-right: 25px;
|
||||
border-radius: 0px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.ui-tabs .ui-tabs-panel {
|
||||
padding: 1.4em 3em 0em 0em;
|
||||
}
|
||||
|
||||
.content a {
|
||||
color: #255792;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.metadata dl {
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
.metadata a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ui-state-default {
|
||||
border: 0px !important;
|
||||
}
|
||||
|
||||
.ui-state-active {
|
||||
padding-bottom: 0px !important;
|
||||
}
|
||||
|
||||
.ui-state-active.ui-state-default {
|
||||
border: 1px solid #cccccc !important;
|
||||
}
|
||||
|
||||
.ui-state-default:hover {
|
||||
background-color: #eeeeee !important;
|
||||
}
|
||||
|
||||
.install {
|
||||
padding: 11px 19px;
|
||||
font-size: 17.5px;
|
||||
-webkit-border-radius: 6px;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
color: #ffffff;
|
||||
background-color: #5bb75b;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.install:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
line-height: 20px;
|
||||
}
|
||||
dd {
|
||||
margin-left: 10px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.featuredIcon {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
table.dataTable tr.active-plugin > td {
|
||||
background-color:#fff !important;
|
||||
}
|
||||
|
||||
table.dataTable tr.active-plugin:hover > td {
|
||||
background-color:#fff !important;
|
||||
}
|
||||
|
||||
table.dataTable tr.inactive-plugin > td {
|
||||
background-color:#ddd !important;
|
||||
}
|
||||
|
||||
table.dataTable tr.inactive-plugin:hover > td {
|
||||
background-color:#ddd !important;
|
||||
}
|
||||
|
||||
.plugin-desc-text {
|
||||
margin-top:0em;
|
||||
margin-bottom:1.5em;
|
||||
}
|
||||
|
||||
.plugin-author {
|
||||
float:left;
|
||||
}
|
||||
|
||||
.plugin-license {
|
||||
float:right;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
.plugin-homepage {
|
||||
font-size:.8em;
|
||||
font-style:italic;
|
||||
}
|
||||
|
||||
table.entityTable tr td .plugin-homepage a {
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
table.entityTable tr td .plugin-homepage a:hover {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
table.entityTable tr td a.uninstall {
|
||||
color:red;
|
||||
text-decoration:none;
|
||||
font-weight:bold;
|
||||
}
|
||||
|
||||
.plugin-version {
|
||||
font-size:80%;
|
||||
font-style:italic;
|
||||
color:#777;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{% extends 'admin.twig' %}
|
||||
{% import '@CorePluginsAdmin/macros.twig' as pluginsMacro %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="pluginslistActionBar">
|
||||
|
||||
<h2 piwik-enriched-headline
|
||||
feature-name="{{ 'CorePluginsAdmin_Marketplace'|translate }}"
|
||||
>{{ 'CorePluginsAdmin_TeaserExtendPiwikByPlugin'|translate }}</h2>
|
||||
|
||||
<div class="infoBox">
|
||||
{{ 'CorePluginsAdmin_BeCarefulUsingPlugins'|translate }}
|
||||
</div>
|
||||
|
||||
{% include "@CorePluginsAdmin/browsePluginsActions.twig" %}
|
||||
</div>
|
||||
|
||||
{% if not isSuperUser %}
|
||||
<div class="pluginslistNonSuperUserHint">
|
||||
{{ 'CorePluginsAdmin_NotAllowedToBrowseMarketplacePlugins'|translate }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="pluginslist">
|
||||
|
||||
{% if plugins|length %}
|
||||
|
||||
{% for plugin in plugins %}
|
||||
|
||||
<div class="plugin">
|
||||
<div class="content" data-pluginName="{{ plugin.name }}">
|
||||
{% include "@CorePluginsAdmin/pluginOverview.twig" %}
|
||||
</div>
|
||||
|
||||
<div class="footer" data-pluginName="{{ plugin.name }}">
|
||||
{% if plugin.featured %}
|
||||
{{ pluginsMacro.featuredIcon('right') }}
|
||||
{% endif %}
|
||||
{% include "@CorePluginsAdmin/pluginMetadata.twig" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% else %}
|
||||
{{ 'CorePluginsAdmin_NoPluginsFound'|translate }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<div class="sort">
|
||||
<a href="{{ linkTo({'sort': 'popular', 'query': ''}) }}" {% if 'popular' == sort %}class="active"{% endif %}>{{ 'CorePluginsAdmin_SortByPopular'|translate }}</a>
|
||||
|
|
||||
<a href="{{ linkTo({'sort': 'newest', 'query': ''}) }}" {% if 'newest' == sort %}class="active"{% endif %}>{{ 'CorePluginsAdmin_SortByNewest'|translate }}</a>
|
||||
|
|
||||
<a href="{{ linkTo({'sort': 'alpha', 'query': ''}) }}" {% if 'alpha' == sort %}class="active"{% endif %}>{{ 'CorePluginsAdmin_SortByAlpha'|translate }}</a>
|
||||
|
|
||||
<form action="{{ linkTo({'sort': ''}) }}" method="POST">
|
||||
<input value="{{ query }}" placeholder="{{ 'General_Search'|translate }}" type="text" name="query"/>
|
||||
<button type="submit">{{ 'General_Search'|translate }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="pluginslistActionBar">
|
||||
|
||||
<h2 piwik-enriched-headline
|
||||
feature-name="{{ 'CorePluginsAdmin_Marketplace'|translate }}"
|
||||
>{{ 'CorePluginsAdmin_TeaserExtendPiwikByTheme'|translate }}</h2>
|
||||
|
||||
<div class="infoBox">
|
||||
{{ 'CorePluginsAdmin_BeCarefulUsingThemes'|translate }}
|
||||
</div>
|
||||
|
||||
{% include "@CorePluginsAdmin/browsePluginsActions.twig" %}
|
||||
</div>
|
||||
|
||||
{% if not isSuperUser %}
|
||||
<div class="pluginslistNonSuperUserHint">
|
||||
{{ 'CorePluginsAdmin_NotAllowedToBrowseMarketplaceThemes'|translate }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="pluginslist themes">
|
||||
|
||||
{% if plugins|length %}
|
||||
{% for plugin in plugins %}
|
||||
|
||||
<div class="plugin">
|
||||
<div class="content" data-pluginName="{{ plugin.name }}">
|
||||
{% include "@CorePluginsAdmin/themeOverview.twig" %}
|
||||
</div>
|
||||
|
||||
<div class="footer" data-pluginName="{{ plugin.name }}">
|
||||
{% include "@CorePluginsAdmin/pluginMetadata.twig" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{{ 'CorePluginsAdmin_NoThemesFound'|translate }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
70
www/analytics/plugins/CorePluginsAdmin/templates/extend.twig
Normal file
70
www/analytics/plugins/CorePluginsAdmin/templates/extend.twig
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% import '@CorePluginsAdmin/macros.twig' as plugins %}
|
||||
|
||||
{% block content %}
|
||||
<div class="extendPlatform">
|
||||
|
||||
<div class="ui-confirm" id="installPluginByUpload">
|
||||
<h2>{{ 'CorePluginsAdmin_TeaserExtendPiwikByUpload'|translate }}</h2>
|
||||
|
||||
<p class="description"> {{ 'CorePluginsAdmin_AllowedUploadFormats'|translate }} </p>
|
||||
|
||||
<form enctype="multipart/form-data"
|
||||
method="post"
|
||||
id="uploadPluginForm"
|
||||
action="{{ linkTo({'action':'uploadPlugin', 'nonce': installNonce}) }}">
|
||||
<input type="file" name="pluginZip">
|
||||
<br />
|
||||
<input class="startUpload" type="submit" value="{{ 'CorePluginsAdmin_UploadZipFile'|translate }}">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="introduction">
|
||||
|
||||
<h2 piwik-enriched-headline
|
||||
feature-name="{{ 'CorePluginsAdmin_Marketplace'|translate }}"
|
||||
>{{ 'CorePluginsAdmin_TeaserExtendPiwik'|translate }}</h2>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_DownloadAndInstallPluginsFromMarketplace'|translate("<a href='?module=Proxy&action=redirect&url=http://plugins.piwik.org/' target='_blank'>", "</a>")|raw }}</p>
|
||||
|
||||
{% set marketplaceSellPluginSubject = 'CorePluginsAdmin_MarketplaceSellPluginSubject'|translate %}
|
||||
<em>{{ 'CorePluginsAdmin_GetEarlyAccessForPaidPlugins'|translate("<a href='mailto:hello@piwik.org?subject=" ~ marketplaceSellPluginSubject ~ "'>", "</a>")|raw }}</em>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="byPlugins">
|
||||
<h3 class="header">{{ 'CorePluginsAdmin_GetNewFunctionality'|translate }}</h3>
|
||||
<span class="callToAction">{{ 'CorePluginsAdmin_ByInstallingNewPluginFromMarketplace'|translate("<a href=" ~ linkTo({'action':'browsePlugins', 'sort': ''}) ~ ">", "</a>")|raw }}</span>
|
||||
|
||||
<p>
|
||||
<a href="{{ linkTo({'action':'browsePlugins', 'sort': ''}) }}"><img class="teaserImage" title="{{ 'CorePluginsAdmin_InstallNewPlugins'|translate }}" alt="{{ 'CorePluginsAdmin_InstallNewPlugins'|translate }}" src="plugins/CorePluginsAdmin/images/plugins.png"/></a>
|
||||
</p>
|
||||
|
||||
<span class="callToAction">
|
||||
{{ 'CorePluginsAdmin_ByWritingOwnPlugin'|translate('<a href="http://developer.piwik.org/guides/getting-started-part-1" target="_blank">', '</a>')|raw }}
|
||||
{% if isSuperUser %}
|
||||
<br/>{{ 'CorePluginsAdmin_OrByUploadingAPlugin'|translate('<a href="#" class="uploadPlugin">', '</a>')|raw }}
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="byThemes">
|
||||
<h3 class="header">{{ 'CorePluginsAdmin_EnjoyAnotherLookAndFeelOfThemes'|translate }}</h3>
|
||||
<span class="callToAction">{{ 'CorePluginsAdmin_ByInstallingNewThemeFromMarketplace'|translate("<a href=" ~ linkTo({'action':'browseThemes', 'sort': ''}) ~ ">", "</a>")|raw }}</span>
|
||||
|
||||
<p>
|
||||
<a href="{{ linkTo({'action':'browseThemes', 'sort': ''}) }}"><img class="teaserImage" alt="{{ 'CorePluginsAdmin_InstallNewThemes'|translate }}" title="{{ 'CorePluginsAdmin_InstallNewThemes'|translate }}" src="plugins/CorePluginsAdmin/images/themes.png"/></a>
|
||||
</p>
|
||||
|
||||
<span class="callToAction">
|
||||
{{ 'CorePluginsAdmin_ByDesigningOwnTheme'|translate('<a href="http://developer.piwik.org/guides/theming" target="_blank">', '</a>')|raw }}
|
||||
{% if isSuperUser %}
|
||||
<br />{{ 'CorePluginsAdmin_OrByUploadingATheme'|translate('<a href="#" class="uploadPlugin">', '</a>')|raw }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div style="max-width:980px;">
|
||||
|
||||
<h2>{{ 'CorePluginsAdmin_InstallingPlugin'|translate(plugin.name) }}</h2>
|
||||
|
||||
<div>
|
||||
|
||||
{% if plugin.isTheme %}
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepDownloadingThemeFromMarketplace'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepUnzippingTheme'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepThemeSuccessfullyInstalled'|translate(plugin.name, plugin.latestVersion) }}</p>
|
||||
|
||||
<p><strong><a href="{{ linkTo({'action': 'activate', 'pluginName': plugin.name, 'nonce': nonce}) }}">{{ 'CorePluginsAdmin_ActionActivateTheme'|translate }}</a></strong>
|
||||
|
||||
|
|
||||
<a href="{{ linkTo({'action': 'browseThemes'}) }}">{{ 'CorePluginsAdmin_BackToExtendPiwik'|translate }}</a></p>
|
||||
|
||||
{% else %}
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepDownloadingPluginFromMarketplace'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepUnzippingPlugin'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepPluginSuccessfullyInstalled'|translate(plugin.name, plugin.latestVersion) }}</p>
|
||||
|
||||
<p><strong><a href="{{ linkTo({'action': 'activate', 'pluginName': plugin.name, 'nonce': nonce}) }}">{{ 'CorePluginsAdmin_ActionActivatePlugin'|translate }}</a></strong>
|
||||
|
||||
|
|
||||
<a href="{{ linkTo({'action': 'browsePlugins'}) }}">{{ 'CorePluginsAdmin_BackToExtendPiwik'|translate }}</a></p>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
256
www/analytics/plugins/CorePluginsAdmin/templates/macros.twig
Normal file
256
www/analytics/plugins/CorePluginsAdmin/templates/macros.twig
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
{% macro tablePluginUpdates(pluginsHavingUpdate, nonce, isTheme) %}
|
||||
|
||||
<div class='entityContainer'>
|
||||
<table class="dataTable entityTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% if isTheme %}{{ 'CorePluginsAdmin_Theme'|translate }}{% else %}{{ 'General_Plugin'|translate }}{% endif %}</th>
|
||||
<th class="num">{{ 'CorePluginsAdmin_Version'|translate }}</th>
|
||||
<th>{{ 'General_Description'|translate }}</th>
|
||||
<th class="status">{{ 'CorePluginsAdmin_Status'|translate }}</th>
|
||||
<th class="action-links">{{ 'General_Action'|translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="plugins">
|
||||
{% for name,plugin in pluginsHavingUpdate %}
|
||||
<tr {% if plugin.isActivated %}class="active-plugin"{% else %}class="inactive-plugin"{% endif %}>
|
||||
<td class="name">
|
||||
<a href="javascript:void(0);" data-pluginName="{{ plugin.name|e('html_attr') }}">
|
||||
{{ plugin.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="vers">
|
||||
{% if plugin.repositoryChangelogUrl %}
|
||||
<a href="javascript:void(0);" title="{{ 'CorePluginsAdmin_Changelog'|translate }}" data-activePluginTab="changelog" data-pluginName="{{ plugin.name|e('html_attr') }}">{{ plugin.currentVersion }} => {{ plugin.latestVersion }}</a>
|
||||
{% else %}
|
||||
{{ plugin.currentVersion }} => {{ plugin.latestVersion }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="desc">
|
||||
{{ plugin.description }}
|
||||
{{ _self.missingRequirementsPleaseUpdateNotice(plugin) }}
|
||||
</td>
|
||||
<td class="status">
|
||||
{% if plugin.isActivated %}
|
||||
{{ 'CorePluginsAdmin_Active'|translate }}
|
||||
{% else %}
|
||||
{{ 'CorePluginsAdmin_Inactive'|translate }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="togl action-links">
|
||||
{% if 0 == plugin.missingRequirements|length %}
|
||||
<a href="{{ linkTo({'action':'updatePlugin', 'pluginName': plugin.name, 'nonce': nonce}) }}">Update</a>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
{% macro pluginDeveloper(owner) %}
|
||||
{% if 'piwik' == owner %}<img title="Piwik" alt="Piwik" style="padding-bottom:2px;height:11px;" src="plugins/Zeitgeist/images/logo-marketplace.png"/>{% else %}{{ owner }}{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro featuredIcon(align='') %}
|
||||
<img class="featuredIcon"
|
||||
title="{{ 'CorePluginsAdmin_FeaturedPlugin'|translate }}"
|
||||
src="plugins/CorePluginsAdmin/images/rating_important.png"
|
||||
align="{{ align }}" />
|
||||
{% endmacro %}
|
||||
|
||||
{% macro pluginsFilter(isTheme, isMarketplaceEnabled) %}
|
||||
|
||||
<p class="pluginsFilter entityContainer">
|
||||
<span class="origin">
|
||||
<strong>{{ 'CorePluginsAdmin_Origin'|translate }}</strong>
|
||||
<a data-filter-origin="all" href="#" class="active">{{ 'General_All'|translate }}<span class="counter"></span></a> |
|
||||
<a data-filter-origin="core" href="#">{{ 'CorePluginsAdmin_OriginCore'|translate }}<span class="counter"></span></a> |
|
||||
<a data-filter-origin="noncore" href="#">{{ 'CorePluginsAdmin_OriginThirdParty'|translate }}<span class="counter"></span></a>
|
||||
</span>
|
||||
|
||||
<span class="status">
|
||||
<strong>{{ 'CorePluginsAdmin_Status'|translate }}</strong>
|
||||
<a data-filter-status="all" href="#" class="active">{{ 'General_All'|translate }}<span class="counter"></span></a> |
|
||||
<a data-filter-status="active" href="#">{{ 'CorePluginsAdmin_Active'|translate }}<span class="counter"></span></a> |
|
||||
<a data-filter-status="inactive" href="#">{{ 'CorePluginsAdmin_Inactive'|translate }}<span class="counter"></span></a>
|
||||
</span>
|
||||
|
||||
{% if isMarketplaceEnabled %}
|
||||
<span class="getNewPlugins">
|
||||
{% if isTheme %}
|
||||
<a href="{{ linkTo({'action':'browseThemes', 'sort': ''}) }}">{{ 'CorePluginsAdmin_InstallNewThemes'|translate }}</a>
|
||||
{% else %}
|
||||
<a href="{{ linkTo({'action':'browsePlugins', 'sort': ''}) }}">{{ 'CorePluginsAdmin_InstallNewPlugins'|translate }}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% endmacro %}
|
||||
|
||||
{% macro missingRequirementsPleaseUpdateNotice(plugin) %}
|
||||
{% if plugin.missingRequirements and 0 < plugin.missingRequirements|length %}
|
||||
{% for req in plugin.missingRequirements -%}
|
||||
<p class="missingRequirementsNotice">
|
||||
{% set requirement = req.requirement|capitalize %}
|
||||
{% if 'Php' == requirement %}
|
||||
{% set requirement = 'PHP' %}
|
||||
{% endif %}
|
||||
{{ 'CorePluginsAdmin_MissingRequirementsNotice'|translate(requirement, req.actualVersion, req.requiredVersion) }}
|
||||
</p>
|
||||
{%- endfor %}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro missingRequirementsInfo(pluginName, metadata, missingRequirements, marketplacePluginNames) %}
|
||||
{% set causedBy = '' %}
|
||||
{% for dependency in missingRequirements %}
|
||||
{% set causedBy = causedBy ~ dependency.requirement|capitalize ~ ' ' ~ dependency.causedBy %}
|
||||
{% if not loop.last %}
|
||||
{% set causedBy = causedBy ~ ', ' %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{{ 'CorePluginsAdmin_PluginRequirement'|translate(pluginName, causedBy) }}
|
||||
|
||||
{% if metadata is defined
|
||||
and metadata.support is defined
|
||||
and metadata.support.email
|
||||
and pluginName not in marketplacePluginNames %}
|
||||
{{ 'CorePluginsAdmin_EmailToEnquireUpdatedVersion'|translate('<a href="mailto:' ~ metadata.support.email|e('html_attr') ~'">' ~ metadata.support.email ~ '</a>', pluginName)|raw }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro tablePlugins(pluginsInfo, pluginNamesHavingSettings, activateNonce, deactivateNonce, uninstallNonce, isTheme, marketplacePluginNames, displayAdminLinks) %}
|
||||
|
||||
<div id="confirmUninstallPlugin" class="ui-confirm">
|
||||
|
||||
<h2 id="uninstallPluginConfirm">{{ 'CorePluginsAdmin_UninstallConfirm'|translate }}</h2>
|
||||
<input role="yes" type="button" value="{{ 'General_Yes'|translate }}"/>
|
||||
<input role="no" type="button" value="{{ 'General_No'|translate }}"/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class='entityContainer'>
|
||||
<table class="dataTable entityTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% if isTheme %}{{ 'CorePluginsAdmin_Theme'|translate }}{% else %}{{ 'General_Plugin'|translate }}{% endif %}</th>
|
||||
<th>{{ 'General_Description'|translate }}</th>
|
||||
<th class="status">{{ 'CorePluginsAdmin_Status'|translate }}</th>
|
||||
{% if (displayAdminLinks) %}
|
||||
<th class="action-links">{{ 'General_Action'|translate }}</th>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="plugins">
|
||||
{% for name,plugin in pluginsInfo %}
|
||||
{% set isZeitgeist = isTheme and name == 'Zeitgeist' %}
|
||||
{% if (plugin.alwaysActivated is defined and not plugin.alwaysActivated) or isTheme %}
|
||||
<tr {% if plugin.activated %}class="active-plugin"{% else %}class="inactive-plugin"{% endif %} data-filter-status="{% if plugin.activated %}active{% else %}inactive{% endif %}" data-filter-origin="{% if plugin.isCorePlugin %}core{% else %}noncore{% endif %}">
|
||||
<td class="name" style="white-space:nowrap;">
|
||||
<a name="{{ name|e('html_attr') }}"></a>
|
||||
{% if not plugin.isCorePlugin and name in marketplacePluginNames -%}
|
||||
<a href="javascript:void(0);"
|
||||
data-pluginName="{{ name|e('html_attr') }}"
|
||||
>{{ name }}</a>
|
||||
{%- else %}
|
||||
{{ name }}
|
||||
{% endif %}
|
||||
<span class="plugin-version" {% if plugin.isCorePlugin %}title="{{ 'CorePluginsAdmin_CorePluginTooltip'|translate }}"{% endif %}>({% if plugin.isCorePlugin %}{{ 'CorePluginsAdmin_OriginCore'|translate }}{% else %}v{{ plugin.info.version }}{% endif %})</span>
|
||||
|
||||
{% if name in pluginNamesHavingSettings %}
|
||||
<br /><br />
|
||||
<a href="{{ linkTo({'module':'CoreAdminHome', 'action': 'pluginSettings'}) }}#{{ name|e('html_attr') }}" class="settingsLink">{{ 'General_Settings'|translate }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="desc">
|
||||
<div class="plugin-desc-missingrequirements">
|
||||
{% if plugin.missingRequirements is defined and plugin.missingRequirements %}
|
||||
{{ _self.missingRequirementsInfo(name, plugin.info, plugin.missingRequirements, marketplacePluginNames) }}
|
||||
<br />
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="plugin-desc-text">
|
||||
|
||||
{{ plugin.info.description|raw|nl2br }}
|
||||
|
||||
{% if plugin.info.homepage|default is not empty and plugin.info.homepage not in [
|
||||
'http://piwik.org', 'http://www.piwik.org', 'http://piwik.org/', 'http://www.piwik.org/'
|
||||
] %}
|
||||
<span class="plugin-homepage">
|
||||
<a href="{{ plugin.info.homepage }}">({{ 'CorePluginsAdmin_PluginHomepage'|translate|replace({' ': ' '})|raw }})</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if plugin.info.license is defined %}
|
||||
<div class="plugin-license">
|
||||
{% if plugin.info.license_homepage is defined %}<a title="{{ 'CorePluginsAdmin_LicenseHomepage'|translate }}" target="_blank" href="{{ plugin.info.license_homepage }}">{% endif %}{{ plugin.info.license }}{% if plugin.info.license_homepage is defined %}</a>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if plugin.info.authors is defined %}
|
||||
<div class="plugin-author">
|
||||
<cite>By
|
||||
{% if plugin.info.authors is defined -%}
|
||||
{% spaceless %}
|
||||
{% for author in plugin.info.authors if author.name %}
|
||||
{% if author.homepage is defined %}
|
||||
<a title="{{ 'CorePluginsAdmin_AuthorHomepage'|translate }}" href="{{ author.homepage }}" target="_blank">{{ author.name }}</a>
|
||||
{% else %}
|
||||
{{ author.name }}
|
||||
{% endif %}
|
||||
{% if loop.index < plugin.info.authors|length %}
|
||||
,
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endspaceless %}
|
||||
{%- endif %}.</cite>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="status" {% if isZeitgeist %}style="border-left-width:0px;"{% endif %}>
|
||||
{% if not isZeitgeist -%}
|
||||
|
||||
{% if plugin.activated %}
|
||||
{{ 'CorePluginsAdmin_Active'|translate }}
|
||||
{% else %}
|
||||
{{ 'CorePluginsAdmin_Inactive'|translate }}
|
||||
{% if plugin.uninstallable and displayAdminLinks %} <br/> - <a data-pluginName="{{ name|escape('html_attr') }}" class="uninstall" href='index.php?module=CorePluginsAdmin&action=uninstall&pluginName={{ name }}&nonce={{ uninstallNonce }}'>{{ 'CorePluginsAdmin_ActionUninstall'|translate }}</a>{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{%- endif %}
|
||||
</td>
|
||||
|
||||
{% if displayAdminLinks %}
|
||||
<td class="togl action-links" {% if isZeitgeist %}style="border-left-width:0px;"{% endif %}>
|
||||
{% if not isZeitgeist -%}
|
||||
|
||||
{% if plugin.invalid is defined or plugin.alwaysActivated %}
|
||||
-
|
||||
{% else %}
|
||||
{% if plugin.activated %}
|
||||
<a href='index.php?module=CorePluginsAdmin&action=deactivate&pluginName={{ name }}&nonce={{ deactivateNonce }}'>{{ 'CorePluginsAdmin_Deactivate'|translate }}</a>
|
||||
{% elseif plugin.missingRequirements %}
|
||||
-
|
||||
{% else %}
|
||||
<a href='index.php?module=CorePluginsAdmin&action=activate&pluginName={{ name }}&nonce={{ activateNonce }}'>{{ 'CorePluginsAdmin_Activate'|translate }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{%- endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% endmacro %}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
{% import '@CorePluginsAdmin/macros.twig' as pluginsMacro %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="pluginDetails">
|
||||
{% if errorMessage %}
|
||||
{{ errorMessage }}
|
||||
{% elseif plugin %}
|
||||
|
||||
{% set latestVersion = plugin.versions[plugin.versions|length - 1] %}
|
||||
|
||||
<div class="header">
|
||||
<div class="intro" style="width:75%;float:left;">
|
||||
<h2>{{ plugin.name }}</h2>
|
||||
<p class="description">
|
||||
{% if plugin.featured %}
|
||||
{{ pluginsMacro.featuredIcon('left') }}
|
||||
{% endif %}
|
||||
{{ plugin.description }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="width:25%;float:left;">
|
||||
|
||||
{% if isSuperUser %}
|
||||
{% if plugin.canBeUpdated and 0 == plugin.missingRequirements|length %}
|
||||
<a class="install update"
|
||||
href="{{ linkTo({'action':'updatePlugin', 'pluginName': plugin.name, 'nonce': updateNonce}) }}"
|
||||
>{{ 'CoreUpdater_UpdateTitle'|translate }}</a>
|
||||
{% elseif plugin.isInstalled %}
|
||||
{% elseif 0 < plugin.missingRequirements|length %}
|
||||
{% else %}
|
||||
<a href="{{ linkTo({'action': 'installPlugin', 'pluginName': plugin.name, 'nonce': installNonce}) }}"
|
||||
class="install">{{ 'CorePluginsAdmin_ActionInstall'|translate }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div style="width:75%;float:left;">
|
||||
|
||||
<div id="pluginDetailsTabs">
|
||||
<ul>
|
||||
<li><a href="#tabs-description">{{ 'General_Description'|translate }}</a></li>
|
||||
{% if latestVersion.readmeHtml.faq %}
|
||||
<li><a href="#tabs-faq">{{ 'General_Faq'|translate }}</a></li>
|
||||
{% endif %}
|
||||
<li><a href="#tabs-changelog">{{ 'CorePluginsAdmin_Changelog'|translate }}</a></li>
|
||||
{% if plugin.screenshots|length %}
|
||||
<li><a href="#tabs-screenshots">{{ 'CorePluginsAdmin_Screenshots'|translate }}</a></li>
|
||||
{% endif %}
|
||||
{% if latestVersion.readmeHtml.support %}
|
||||
<li><a href="#tabs-support">{{ 'CorePluginsAdmin_Support'|translate }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<div id="tabs-description">
|
||||
{{ pluginsMacro.missingRequirementsPleaseUpdateNotice(plugin) }}
|
||||
{{ latestVersion.readmeHtml.description|raw }}
|
||||
</div>
|
||||
|
||||
{% if latestVersion.readmeHtml.faq %}
|
||||
<div id="tabs-faq">
|
||||
{{ latestVersion.readmeHtml.faq|raw }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div id="tabs-changelog">
|
||||
{{ pluginsMacro.missingRequirementsPleaseUpdateNotice(plugin) }}
|
||||
{% if plugin.canBeUpdated %}
|
||||
<p class="updateAvailableNotice">{{ 'CorePluginsAdmin_PluginUpdateAvailable'|translate(plugin.currentVersion, plugin.latestVersion) }}
|
||||
{% if plugin.repositoryChangelogUrl %}<a target="_blank" href="{{ plugin.repositoryChangelogUrl }}">{{ 'CorePluginsAdmin_ViewRepositoryChangelog'|translate }}</a>{% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if latestVersion.readmeHtml.changelog %}
|
||||
{{ latestVersion.readmeHtml.changelog|raw }}
|
||||
{% endif %}
|
||||
|
||||
<h3>{{ 'CorePluginsAdmin_History'|translate }}</h3>
|
||||
|
||||
<ul>
|
||||
{% for version in plugin.versions|reverse %}
|
||||
<li>
|
||||
{% set versionName %}
|
||||
<strong>
|
||||
{% if version.repositoryChangelogUrl %}
|
||||
<a target="_blank" title="{{ 'CorePluginsAdmin_Changelog'|translate }}" href="{{ version.repositoryChangelogUrl }}">{{ version.name }}</a>
|
||||
{% else %}
|
||||
{{ version.name }}
|
||||
{% endif %}
|
||||
</strong>
|
||||
{% endset %}
|
||||
{{ 'CorePluginsAdmin_PluginVersionInfo'|translate(versionName, version.release)|raw }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% if plugin.screenshots|length %}
|
||||
<div id="tabs-screenshots">
|
||||
<div class="thumbnails">
|
||||
{% for screenshot in plugin.screenshots %}
|
||||
<div class="thumbnail">
|
||||
<a href="{{ screenshot }}" target="_blank"><img src="{{ screenshot }}?w=400" width="400" alt=""></a>
|
||||
<p>
|
||||
{{ screenshot|split('/')|last|replace({'_': ' ', '.png': '', '.jpg': '', '.jpeg': ''}) }}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if latestVersion.readmeHtml.support %}
|
||||
<div id="tabs-support">
|
||||
|
||||
{{ latestVersion.readmeHtml.support|raw }}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="metadata" style="width:25%;float:left;">
|
||||
<p><br /></p>
|
||||
<dl>
|
||||
<dt>{{ 'CorePluginsAdmin_Version'|translate }}</dt>
|
||||
<dd>{{ plugin.latestVersion }}</dd>
|
||||
<dt>{{ 'CorePluginsAdmin_PluginKeywords'|translate }}</dt>
|
||||
<dd>{{ plugin.keywords|join(', ') }}</dd>
|
||||
<dt>{{ 'CorePluginsAdmin_LastUpdated'|translate }}</dt>
|
||||
<dd>{{ plugin.lastUpdated }}</dd>
|
||||
<dt>{{ 'General_Downloads'|translate }}</dt>
|
||||
<dd title="{{ 'CorePluginsAdmin_NumDownloadsLatestVersion'|translate(latestVersion.numDownloads|number_format) }}">{{ plugin.numDownloads }}</dd>
|
||||
<dt>{{ 'CorePluginsAdmin_Developer'|translate }}</dt>
|
||||
<dd>{{ pluginsMacro.pluginDeveloper(plugin.owner) }}</dd>
|
||||
<dt>{{ 'CorePluginsAdmin_Authors'|translate }}</dt>
|
||||
<dd>{% for author in plugin.authors if author.name %}
|
||||
|
||||
{% spaceless %}
|
||||
{% if author.homepage %}
|
||||
<a target="_blank" href="{{ author.homepage }}">{{ author.name }}</a>
|
||||
{% elseif author.email %}
|
||||
<a href="mailto:{{ author.email|escape('url') }}">{{ author.name }}</a>
|
||||
{% else %}
|
||||
{{ author.name }}
|
||||
{% endif %}
|
||||
|
||||
{% if loop.index < plugin.authors|length %}
|
||||
,
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
|
||||
{% endfor %}
|
||||
</dd>
|
||||
<dt>{{ 'CorePluginsAdmin_Websites'|translate }}</dt>
|
||||
<dd>
|
||||
{% if plugin.homepage %}
|
||||
<a target="_blank" href="{{ plugin.homepage }}">{{ 'CorePluginsAdmin_PluginWebsite'|translate }}</a>,
|
||||
{% endif %}
|
||||
<a target="_blank" href="{{ plugin.repositoryUrl }}">GitHub</a></dd>
|
||||
{% if plugin.activity %}
|
||||
<dt>{{ 'CorePluginsAdmin_Activity'|translate }}</dt>
|
||||
<dd>
|
||||
{{ plugin.activity.numCommits }} commits
|
||||
|
||||
{% if plugin.activity.numContributors > 1 %}
|
||||
{{ 'CorePluginsAdmin_ByXDevelopers'|translate(plugin.activity.numContributors) }}
|
||||
{% endif %}
|
||||
{% if plugin.activity.lastCommitDate %}
|
||||
{{ 'CorePluginsAdmin_LastCommitTime'|translate(plugin.activity.lastCommitDate) }}
|
||||
{% endif %}</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
|
||||
var active = 0;
|
||||
{% if activeTab %}
|
||||
var $activeTab = $('#tabs-{{ activeTab|e('js') }}');
|
||||
if ($activeTab) {
|
||||
active = $activeTab.index() - 1;
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
$( "#pluginDetailsTabs" ).tabs({active: active >= 0 ? active : 0});
|
||||
|
||||
$('.pluginDetails a').each(function (index, a) {
|
||||
var link = $(a).attr('href');
|
||||
|
||||
if (link && 0 === link.indexOf('http')) {
|
||||
$(a).attr('target', '_blank');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{% import '@CorePluginsAdmin/macros.twig' as plugins %}
|
||||
|
||||
<hr class="metadataSeparator"/>
|
||||
<ul class="metadata">
|
||||
<li class="odd">{{ 'CorePluginsAdmin_Version'|translate }}: <strong>{{ plugin.latestVersion }}</strong></li>
|
||||
<li class="even">{{ 'CorePluginsAdmin_Updated'|translate }}: <strong>{{ plugin.lastUpdated }}</strong></li>
|
||||
<li class="odd">{{ 'General_Downloads'|translate }}: <strong>{{ plugin.numDownloads }}</strong></li>
|
||||
<li class="even">{{ 'CorePluginsAdmin_Developer'|translate }}: <strong>{{ plugins.pluginDeveloper(plugin.owner) }}</strong></li>
|
||||
</ul>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{% import '@CorePluginsAdmin/macros.twig' as plugins %}
|
||||
|
||||
{% if isSuperUser %}
|
||||
{% if plugin.canBeUpdated and 0 == plugin.missingRequirements|length %}
|
||||
<a class="update"
|
||||
href="{{ linkTo({'action':'updatePlugin', 'pluginName': plugin.name, 'nonce': updateNonce}) }}"
|
||||
>{{ 'CoreUpdater_UpdateTitle'|translate }}</a>
|
||||
{% elseif plugin.isInstalled %}
|
||||
<span class="install">{{ 'General_Installed'|translate }}</span>
|
||||
{% elseif 0 < plugin.missingRequirements|length %}
|
||||
{% else %}
|
||||
<a href="{{ linkTo({'action': 'installPlugin', 'pluginName': plugin.name, 'nonce': installNonce}) }}"
|
||||
class="install">{{ 'CorePluginsAdmin_ActionInstall'|translate }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<h3 class="header" title="{{ 'General_MoreDetails'|translate }}">
|
||||
<a href="javascript:void(0);" class="more">{{ plugin.name }}</a>
|
||||
</h3>
|
||||
<p class="description">{{ plugin.description }}
|
||||
<br />
|
||||
<a href="javascript:void(0);" title="{{ 'General_MoreDetails'|translate }}" class="more">>> {{ 'General_MoreLowerCase'|translate }}</a>
|
||||
</p>
|
||||
|
||||
{% if plugin.canBeUpdated %}
|
||||
<p class="updateAvailableNotice" data-activePluginTab="changelog">{{ 'CorePluginsAdmin_PluginUpdateAvailable'|translate(plugin.currentVersion, plugin.latestVersion) }}</p>
|
||||
{% endif %}
|
||||
|
||||
{{ plugins.missingRequirementsPleaseUpdateNotice(plugin) }}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% import '@CorePluginsAdmin/macros.twig' as plugins %}
|
||||
|
||||
{% block content %}
|
||||
<div style="max-width:980px;">
|
||||
|
||||
{% if pluginsHavingUpdate|length %}
|
||||
<h2>{{ pluginsHavingUpdate|length }} Update(s) available</h2>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_InfoPluginUpdateIsRecommended'|translate }}</p>
|
||||
|
||||
{{ plugins.tablePluginUpdates(pluginsHavingUpdate, updateNonce, activateNonce, 0) }}
|
||||
{% endif %}
|
||||
|
||||
<h2 piwik-enriched-headline>{{ 'CorePluginsAdmin_PluginsManagement'|translate }}</h2>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_MainDescription'|translate }}
|
||||
|
||||
{% if not isPluginsAdminEnabled %}
|
||||
<br/>{{ 'CorePluginsAdmin_DoMoreContactPiwikAdmins'|translate }}
|
||||
{% endif %}
|
||||
|
||||
</p>
|
||||
|
||||
{{ plugins.pluginsFilter(false, isMarketplaceEnabled) }}
|
||||
|
||||
{{ plugins.tablePlugins(pluginsInfo, pluginNamesHavingSettings, activateNonce, deactivateNonce, uninstallNonce, false, marketplacePluginNames, isPluginsAdminEnabled) }}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
114
www/analytics/plugins/CorePluginsAdmin/templates/safemode.twig
Normal file
114
www/analytics/plugins/CorePluginsAdmin/templates/safemode.twig
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
background-color: white;
|
||||
}
|
||||
td {
|
||||
border: 1px solid #ccc;
|
||||
border-collapse: collapse;
|
||||
padding: 5px;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border: 0px;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>A fatal error occurred</h1>
|
||||
|
||||
<div style="width: 640px">
|
||||
|
||||
{% if not isAnonymousUser %}
|
||||
<p>
|
||||
The following error just broke Piwik{% if showVersion %} (v{{ piwikVersion }}){% endif %}:
|
||||
<pre>{{ lastError.message }}</pre>
|
||||
in
|
||||
<pre>{{ lastError.file }} line {{ lastError.line }}</pre>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if isSuperUser %}
|
||||
<p>
|
||||
If this error continues to happen, there is a good chance to fix this issue by disabling one or more of
|
||||
the Third-Party plugins. You can enable them again in the
|
||||
<a target="_blank" href="index.php?module=CorePluginsAdmin&action=plugins">Plugins</a> or <a target="_blank" href="index.php?module=CorePluginsAdmin&action=themes">Themes</a> page under
|
||||
settings at any time.
|
||||
|
||||
{% if pluginCausesIssue %}
|
||||
Based on the error message, the issue is probably caused by the plugin <strong>{{ pluginCausesIssue }}</strong>.
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<table>
|
||||
{% for pluginName, plugin in plugins if plugin.uninstallable and plugin.activated %}
|
||||
<tr {% if loop.index is divisibleby(2) %}style="background-color: #eeeeee"{% endif %}>
|
||||
<td style="min-width:200px;">
|
||||
{{ pluginName }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="index.php?module=CorePluginsAdmin&action=deactivate&pluginName={{ pluginName }}&nonce={{ deactivateNonce }}"
|
||||
target="_blank">deactivate</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% set uninstalledPluginsFound = false %}
|
||||
{% for pluginName, plugin in plugins if plugin.uninstallable and not plugin.activated %}
|
||||
{% set uninstalledPluginsFound = true %}
|
||||
{% endfor %}
|
||||
|
||||
{% if uninstalledPluginsFound %}
|
||||
|
||||
<p>
|
||||
If this error still occurs after disabling all plugins, you might want to consider uninstalling some
|
||||
plugins. Keep in mind: The plugin will be completely removed from your platform.
|
||||
</p>
|
||||
|
||||
<table>
|
||||
{% for pluginName, plugin in plugins if plugin.uninstallable and not plugin.activated %}
|
||||
<tr {% if loop.index is divisibleby(2) %}style="background-color: #eeeeee"{% endif %}>
|
||||
<td style="min-width:200px;">
|
||||
{{ pluginName }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="index.php?module=CorePluginsAdmin&action=uninstall&pluginName={{ pluginName }}&nonce={{ uninstallNonce }}"
|
||||
target="_blank" onclick="return confirm('{{ 'CorePluginsAdmin_UninstallConfirm'|translate(pluginName)|e('js') }}')">uninstall</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
<br />
|
||||
We appreciate if you send the
|
||||
<a href="mailto:hello@piwik.org?subject={{ 'Fatal error in Piwik ' ~ piwikVersion|e('url') }}&body={{ lastError.message|e('url') }}%20in%20{{ lastError.file|e('url') }}%20{{ lastError.line|e('url') }}%20using%20PHP%20{{ constant('PHP_VERSION') }}">error report</a>
|
||||
to the Piwik team.
|
||||
</p>
|
||||
|
||||
{% elseif isAnonymousUser %}
|
||||
|
||||
<p>Please contact the system administrator.</p>
|
||||
|
||||
{% else %}
|
||||
<p>
|
||||
If this error continues to happen you may want to send an
|
||||
<a href="mailto:{{ emailSuperUser }}?subject={{ 'Fatal error in Piwik ' ~ piwikVersion|e('url') }}&body={{ lastError.message|e('url') }}%20in%20{{ lastError.file|e('url') }}%20{{ lastError.line|e('url') }}%20using%20PHP%20{{ constant('PHP_VERSION') }}">error report</a>
|
||||
to your system administrator.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{% import '@CorePluginsAdmin/macros.twig' as plugins %}
|
||||
|
||||
{% if isSuperUser %}
|
||||
{% if plugin.canBeUpdated and 0 == plugin.missingRequirements|length %}
|
||||
<a href="{{ linkTo({'action':'updatePlugin', 'pluginName': plugin.name, 'nonce': updateNonce}) }}"
|
||||
class="update"
|
||||
>{{ 'CoreUpdater_UpdateTitle'|translate }}</a>
|
||||
{% elseif plugin.isInstalled %}
|
||||
<span class="install">{{ 'General_Installed'|translate }}</span>
|
||||
{% elseif 0 < plugin.missingRequirements|length %}
|
||||
{% else %}
|
||||
<a href="{{ linkTo({'action': 'installPlugin', 'pluginName': plugin.name, 'nonce': installNonce}) }}"
|
||||
class="install">{{ 'CorePluginsAdmin_ActionInstall'|translate }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<h3 class="header" title="{{ 'General_MoreDetails'|translate }}">
|
||||
<a href="javascript:void(0);" class="more">{{ plugin.name }}</a>
|
||||
</h3>
|
||||
|
||||
<p class="description">{% if plugin.featured %}{{ plugins.featuredIcon('right') }}{% endif %}{{ plugin.description }}</p>
|
||||
|
||||
{% if plugin.canBeUpdated %}
|
||||
<p class="updateAvailableNotice">{{ 'CorePluginsAdmin_PluginUpdateAvailable'|translate(plugin.currentVersion, plugin.latestVersion) }}</p>
|
||||
{% endif %}
|
||||
|
||||
{{ plugins.missingRequirementsPleaseUpdateNotice(plugin) }}
|
||||
|
||||
<a href="javascript:void(0);" class="more"><img title="{{ 'General_MoreDetails'|translate }}"
|
||||
class="preview" src="{{ plugin.screenshots|first }}?w=250&h=250"/></a>
|
||||
33
www/analytics/plugins/CorePluginsAdmin/templates/themes.twig
Normal file
33
www/analytics/plugins/CorePluginsAdmin/templates/themes.twig
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% import '@CorePluginsAdmin/macros.twig' as plugins %}
|
||||
|
||||
{% block content %}
|
||||
<div style="max-width:980px;">
|
||||
|
||||
{% if pluginsHavingUpdate|length %}
|
||||
<h2>{{ 'CorePluginsAdmin_NumUpdatesAvailable'|translate(pluginsHavingUpdate|length) }}</h2>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_InfoThemeUpdateIsRecommended'|translate }}</p>
|
||||
|
||||
{{ plugins.tablePluginUpdates(pluginsHavingUpdate, updateNonce, true) }}
|
||||
{% endif %}
|
||||
|
||||
<h2 piwik-enriched-headline>{{ 'CorePluginsAdmin_ThemesManagement'|translate }}</h2>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_ThemesDescription'|translate }}
|
||||
{% if otherUsersCount > 0 %}
|
||||
<br/> {{ 'CorePluginsAdmin_InfoThemeIsUsedByOtherUsersAsWell'|translate(otherUsersCount, themeEnabled) }}
|
||||
{% endif %}
|
||||
{% if not isPluginsAdminEnabled %}
|
||||
<br/>{{ 'CorePluginsAdmin_DoMoreContactPiwikAdmins'|translate }}
|
||||
{% endif %}
|
||||
|
||||
</p>
|
||||
|
||||
{{ plugins.pluginsFilter(true, isMarketplaceEnabled) }}
|
||||
|
||||
{{ plugins.tablePlugins(pluginsInfo, pluginNamesHavingSettings, activateNonce, deactivateNonce, uninstallNonce, true, marketplacePluginNames, isPluginsAdminEnabled ) }}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div style="max-width:980px;">
|
||||
|
||||
<h2>{{ 'CorePluginsAdmin_UpdatingPlugin'|translate(plugin.name) }}</h2>
|
||||
|
||||
<div>
|
||||
|
||||
{% if plugin.isTheme %}
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepDownloadingThemeFromMarketplace'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepUnzippingTheme'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepReplaceExistingTheme'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepThemeSuccessfullyUpdated'|translate(plugin.name, plugin.latestVersion) }}</p>
|
||||
|
||||
{% else %}
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepDownloadingPluginFromMarketplace'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepUnzippingPlugin'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepReplaceExistingPlugin'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepPluginSuccessfullyUpdated'|translate(plugin.name, plugin.latestVersion) }}</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<p><a href="{{ linkTo({'action': 'plugins'}) }}">{{ 'General_Plugins'|translate }}</a>
|
||||
|
|
||||
<a href="{{ linkTo({'action': 'themes'}) }}">{{ 'CorePluginsAdmin_Themes'|translate }}</a>
|
||||
|
|
||||
<a href="{{ linkTo({'action': 'extend'}) }}">{{ 'CorePluginsAdmin_Marketplace'|translate }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{% extends 'admin.twig' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div style="max-width:980px;">
|
||||
|
||||
<div>
|
||||
<h2>{{ 'CorePluginsAdmin_InstallingPlugin'|translate(plugin.name) }}</h2>
|
||||
|
||||
{% if plugin.isTheme %}
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepUnzippingTheme'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepThemeSuccessfullyInstalled'|translate(plugin.name, plugin.version) }}</p>
|
||||
|
||||
<p>
|
||||
{% if not plugin.isActivated %}
|
||||
<strong><a href="{{ linkTo({'action': 'activate', 'pluginName': plugin.name, 'nonce': nonce}) }}">{{ 'CorePluginsAdmin_ActionActivateTheme'|translate }}</a></strong>
|
||||
|
||||
|
|
||||
{% endif %}
|
||||
<a href="{{ linkTo({'action': 'extend'}) }}">{{ 'CorePluginsAdmin_BackToExtendPiwik'|translate }}</a>
|
||||
</p>
|
||||
|
||||
{% else %}
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepUnzippingPlugin'|translate }}</p>
|
||||
|
||||
<p>{{ 'CorePluginsAdmin_StepPluginSuccessfullyInstalled'|translate(plugin.name, plugin.version) }}</p>
|
||||
|
||||
<p>
|
||||
{% if not plugin.isActivated %}
|
||||
<strong><a href="{{ linkTo({'action': 'activate', 'pluginName': plugin.name, 'nonce': nonce}) }}">{{ 'CorePluginsAdmin_ActionActivatePlugin'|translate }}</a></strong>
|
||||
|
||||
|
|
||||
{% endif %}
|
||||
<a href="{{ linkTo({'action': 'extend'}) }}">{{ 'CorePluginsAdmin_BackToExtendPiwik'|translate }}</a>
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue