first commit
This commit is contained in:
@@ -0,0 +1,629 @@
|
||||
<?php
|
||||
|
||||
namespace Account;
|
||||
|
||||
use Analyst\Analyst;
|
||||
use Analyst\ApiRequestor;
|
||||
use Analyst\Cache\DatabaseCache;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Http\Requests\ActivateRequest;
|
||||
use Analyst\Http\Requests\DeactivateRequest;
|
||||
use Analyst\Http\Requests\InstallRequest;
|
||||
use Analyst\Http\Requests\OptInRequest;
|
||||
use Analyst\Http\Requests\OptOutRequest;
|
||||
use Analyst\Http\Requests\UninstallRequest;
|
||||
use Analyst\Notices\Notice;
|
||||
use Analyst\Notices\NoticeFactory;
|
||||
use Analyst\Contracts\TrackerContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class Account
|
||||
*
|
||||
* This is plugin's account object
|
||||
*/
|
||||
class Account implements TrackerContract
|
||||
{
|
||||
/**
|
||||
* Account id
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Basename of plugin
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Whether plugin is active or not
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInstalled = false;
|
||||
|
||||
/**
|
||||
* Is user sign in for data tracking
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isOptedIn = false;
|
||||
|
||||
/**
|
||||
* Is user accepted permissions grant
|
||||
* for collection site data
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isSigned = false;
|
||||
|
||||
/**
|
||||
* Is user ever resolved install modal window?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInstallResolved = false;
|
||||
|
||||
/**
|
||||
* Public secret code
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $clientSecret;
|
||||
|
||||
/**
|
||||
* @var AccountData
|
||||
*/
|
||||
protected $data;
|
||||
|
||||
/**
|
||||
* Base plugin path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $basePluginPath;
|
||||
|
||||
/**
|
||||
* @var RequestorContract
|
||||
*/
|
||||
protected $requestor;
|
||||
|
||||
/**
|
||||
* @var Collector
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* Account constructor.
|
||||
* @param $id
|
||||
* @param $secret
|
||||
* @param $baseDir
|
||||
*/
|
||||
public function __construct($id, $secret, $baseDir)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->clientSecret = $secret;
|
||||
|
||||
$this->path = $baseDir;
|
||||
|
||||
$this->basePluginPath = plugin_basename($baseDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->data->setPath($path);
|
||||
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOptedIn()
|
||||
{
|
||||
return $this->isOptedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isOptedIn
|
||||
*/
|
||||
public function setIsOptedIn($isOptedIn)
|
||||
{
|
||||
$this->data->setIsOptedIn($isOptedIn);
|
||||
|
||||
$this->isOptedIn = $isOptedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether plugin is active
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isActive()
|
||||
{
|
||||
return is_plugin_active($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isInstalled()
|
||||
{
|
||||
return $this->isInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isInstalled
|
||||
*/
|
||||
public function setIsInstalled($isInstalled)
|
||||
{
|
||||
$this->data->setIsInstalled($isInstalled);
|
||||
|
||||
$this->isInstalled = $isInstalled;
|
||||
}
|
||||
|
||||
protected function verifyNonceAndPerms() {
|
||||
|
||||
$capabilities = [
|
||||
'activate_plugins',
|
||||
'edit_plugins',
|
||||
'install_plugins',
|
||||
'update_plugins',
|
||||
'delete_plugins',
|
||||
'manage_network_plugins',
|
||||
'upload_plugins'
|
||||
];
|
||||
|
||||
// Allow if has any of above permissions
|
||||
$hasPerms = false;
|
||||
foreach ($capabilities as $i => $cap) {
|
||||
if (current_user_can($cap)) {
|
||||
$hasPerms = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasPerms == false) {
|
||||
wp_send_json_error(['message' => 'no_permissions']);
|
||||
die;
|
||||
}
|
||||
|
||||
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'analyst_opt_ajax_nonce')) {
|
||||
wp_send_json_error(['message' => 'invalid_nonce']);
|
||||
die;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Should register activation and deactivation
|
||||
* event hooks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerHooks()
|
||||
{
|
||||
register_activation_hook($this->basePluginPath, [&$this, 'onActivePluginListener']);
|
||||
register_uninstall_hook($this->basePluginPath, ['Account\Account', 'onUninstallPluginListener']);
|
||||
|
||||
$this->addFilter('plugin_action_links', [&$this, 'onRenderActionLinksHook']);
|
||||
|
||||
$this->addAjax('analyst_opt_in', [&$this, 'onOptInListener']);
|
||||
$this->addAjax('analyst_opt_out', [&$this, 'onOptOutListener']);
|
||||
$this->addAjax('analyst_plugin_deactivate', [&$this, 'onDeactivatePluginListener']);
|
||||
$this->addAjax('analyst_install', [&$this, 'onInstallListener']);
|
||||
$this->addAjax('analyst_skip_install', [&$this, 'onSkipInstallListener']);
|
||||
$this->addAjax('analyst_install_verified', [&$this, 'onInstallVerifiedListener']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when admin activates plugin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onActivePluginListener()
|
||||
{
|
||||
if (!$this->isInstallResolved()) {
|
||||
DatabaseCache::getInstance()->put('plugin_to_install', $this->id);
|
||||
}
|
||||
|
||||
if (!$this->isAllowingLogging()) return;
|
||||
|
||||
ActivateRequest::make($this->collector, $this->id, $this->path)
|
||||
->execute($this->requestor);
|
||||
|
||||
$this->setIsInstalled(true);
|
||||
|
||||
AccountDataFactory::syncData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when admin deactivates plugin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onDeactivatePluginListener()
|
||||
{
|
||||
$this->verifyNonceAndPerms();
|
||||
|
||||
if (!$this->isAllowingLogging()) return;
|
||||
|
||||
$question = isset($_POST['question']) ? sanitize_text_field(stripslashes($_POST['question'])) : null;
|
||||
$reason = isset($_POST['reason']) ? sanitize_text_field(stripslashes($_POST['reason'])) : null;
|
||||
|
||||
DeactivateRequest::make($this->collector, $this->id, $this->path, $question, $reason)
|
||||
->execute($this->requestor);
|
||||
|
||||
$this->setIsInstalled(false);
|
||||
|
||||
AccountDataFactory::syncData();
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when user opted in
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onOptInListener()
|
||||
{
|
||||
$this->verifyNonceAndPerms();
|
||||
|
||||
OptInRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
|
||||
|
||||
$this->setIsOptedIn(true);
|
||||
|
||||
AccountDataFactory::syncData();
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when user opted out
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onOptOutListener()
|
||||
{
|
||||
$this->verifyNonceAndPerms();
|
||||
|
||||
OptOutRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
|
||||
|
||||
$this->setIsOptedIn(false);
|
||||
|
||||
AccountDataFactory::syncData();
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when user accept opt-in
|
||||
* at first time
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onInstallListener()
|
||||
{
|
||||
$this->verifyNonceAndPerms();
|
||||
|
||||
$cache = DatabaseCache::getInstance();
|
||||
|
||||
// Set flag to true which indicates that install is resolved
|
||||
// also remove install plugin id from cache
|
||||
$this->setIsInstallResolved(true);
|
||||
$cache->delete('plugin_to_install');
|
||||
|
||||
InstallRequest::make($this->collector, $this->id, $this->path)->execute($this->requestor);
|
||||
|
||||
$this->setIsSigned(true);
|
||||
|
||||
$this->setIsOptedIn(true);
|
||||
|
||||
$factory = NoticeFactory::instance();
|
||||
|
||||
$message = sprintf('Please confirm your email by clicking on the link we sent to %s. This makes sure you’re not a bot.', $this->collector->getGeneralEmailAddress());
|
||||
|
||||
$notificationId = uniqid();
|
||||
|
||||
$notice = Notice::make(
|
||||
$notificationId,
|
||||
$this->getId(),
|
||||
$message,
|
||||
$this->collector->getPluginName($this->path)
|
||||
);
|
||||
|
||||
$factory->addNotice($notice);
|
||||
|
||||
AccountDataFactory::syncData();
|
||||
|
||||
// Set email confirmation notification id to cache
|
||||
// se we can extract and remove it when user confirmed email
|
||||
$cache->put(
|
||||
sprintf('account_email_confirmation_%s', $this->getId()),
|
||||
$notificationId
|
||||
);
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when user skipped installation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onSkipInstallListener()
|
||||
{
|
||||
$this->verifyNonceAndPerms();
|
||||
|
||||
// Set flag to true which indicates that install is resolved
|
||||
// also remove install plugin id from cache
|
||||
$this->setIsInstallResolved(true);
|
||||
DatabaseCache::getInstance()->delete('plugin_to_install');
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when user delete plugin through admin panel.
|
||||
* This action will happen if admin at least once
|
||||
* activated the plugin.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function onUninstallPluginListener()
|
||||
{
|
||||
$factory = AccountDataFactory::instance();
|
||||
|
||||
$pluginFile = substr(current_filter(), strlen( 'uninstall_' ));
|
||||
|
||||
$account = $factory->getAccountDataByBasePath($pluginFile);
|
||||
|
||||
// If account somehow is not found, exit the execution
|
||||
if (!$account) return;
|
||||
|
||||
$analyst = Analyst::getInstance();
|
||||
|
||||
$collector = new Collector($analyst);
|
||||
|
||||
$requestor = new ApiRequestor($account->getId(), $account->getSecret(), $analyst->getApiBase());
|
||||
|
||||
// Just send request to log uninstall event not caring about response
|
||||
UninstallRequest::make($collector, $account->getId(), $account->getPath())->execute($requestor);
|
||||
|
||||
$factory->sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when used verified his account
|
||||
*/
|
||||
public function onInstallVerifiedListener()
|
||||
{
|
||||
$this->verifyNonceAndPerms();
|
||||
|
||||
$factory = NoticeFactory::instance();
|
||||
|
||||
$notice = Notice::make(
|
||||
uniqid(),
|
||||
$this->getId(),
|
||||
'Thank you for confirming your email.',
|
||||
$this->collector->getPluginName($this->path)
|
||||
);
|
||||
|
||||
$factory->addNotice($notice);
|
||||
|
||||
// Remove confirmation notification
|
||||
$confirmationNotificationId = DatabaseCache::getInstance()->pop(sprintf('account_email_confirmation_%s', $this->getId()));
|
||||
$factory->remove($confirmationNotificationId);
|
||||
|
||||
AccountDataFactory::syncData();
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fire when wp renders plugin
|
||||
* action buttons
|
||||
*
|
||||
* @param $defaultLinks
|
||||
* @return array
|
||||
*/
|
||||
public function onRenderActionLinksHook($defaultLinks)
|
||||
{
|
||||
$customLinks = [];
|
||||
|
||||
$customLinks[] = $this->isOptedIn()
|
||||
? '<a class="analyst-action-opt analyst-opt-out" analyst-plugin-id="' . $this->getId() . '" analyst-plugin-signed="' . (int) $this->isSigned() . '">Opt Out</a>'
|
||||
: '<a class="analyst-action-opt analyst-opt-in" analyst-plugin-id="' . $this->getId() . '" analyst-plugin-signed="' . (int) $this->isSigned() . '">Opt In</a>';
|
||||
|
||||
// Append anchor to find specific deactivation link
|
||||
if (isset($defaultLinks['deactivate'])) {
|
||||
$defaultLinks['deactivate'] .= '<span analyst-plugin-id="' . $this->getId() . '" analyst-plugin-opted-in="' . (int) $this->isOptedIn() . '"></span>';
|
||||
}
|
||||
|
||||
return array_merge($customLinks, $defaultLinks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccountData
|
||||
*/
|
||||
public function getData()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AccountData $data
|
||||
*/
|
||||
public function setData(AccountData $data)
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
$this->setIsOptedIn($data->isOptedIn());
|
||||
$this->setIsInstalled($data->isInstalled());
|
||||
$this->setIsSigned($data->isSigned());
|
||||
$this->setIsInstallResolved($data->isInstallResolved());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves valid action name
|
||||
* based on client id
|
||||
*
|
||||
* @param $action
|
||||
* @return string
|
||||
*/
|
||||
private function resolveActionName($action)
|
||||
{
|
||||
return sprintf('%s_%s', $action, $this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register action for current plugin
|
||||
*
|
||||
* @param $action
|
||||
* @param $callback
|
||||
*/
|
||||
private function addFilter($action, $callback)
|
||||
{
|
||||
$validAction = sprintf('%s_%s', $action, $this->basePluginPath);
|
||||
|
||||
add_filter($validAction, $callback, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ajax action for current plugin
|
||||
*
|
||||
* @param $action
|
||||
* @param $callback
|
||||
* @param bool $raw Format action ??
|
||||
*/
|
||||
private function addAjax($action, $callback, $raw = false)
|
||||
{
|
||||
$validAction = $raw ? $action : sprintf('%s%s', 'wp_ajax_', $this->resolveActionName($action));
|
||||
|
||||
add_action($validAction, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSigned()
|
||||
{
|
||||
return $this->isSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isSigned
|
||||
*/
|
||||
public function setIsSigned($isSigned)
|
||||
{
|
||||
$this->data->setIsSigned($isSigned);
|
||||
|
||||
$this->isSigned = $isSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RequestorContract
|
||||
*/
|
||||
public function getRequestor()
|
||||
{
|
||||
return $this->requestor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestorContract $requestor
|
||||
*/
|
||||
public function setRequestor(RequestorContract $requestor)
|
||||
{
|
||||
$this->requestor = $requestor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientSecret()
|
||||
{
|
||||
return $this->clientSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collector
|
||||
*/
|
||||
public function getCollector()
|
||||
{
|
||||
return $this->collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collector $collector
|
||||
*/
|
||||
public function setCollector(Collector $collector)
|
||||
{
|
||||
$this->collector = $collector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we allowing logging
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isAllowingLogging()
|
||||
{
|
||||
return $this->isOptedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBasePluginPath()
|
||||
{
|
||||
return $this->basePluginPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isInstallResolved()
|
||||
{
|
||||
return $this->isInstallResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isInstallResolved
|
||||
*/
|
||||
public function setIsInstallResolved($isInstallResolved)
|
||||
{
|
||||
$this->data->setIsInstallResolved($isInstallResolved);
|
||||
|
||||
$this->isInstallResolved = $isInstallResolved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
|
||||
namespace Account;
|
||||
|
||||
/**
|
||||
* Class AccountData is the data holder
|
||||
* for Analyst\Account\Account class
|
||||
* which is unserialized from database
|
||||
*/
|
||||
class AccountData
|
||||
{
|
||||
/**
|
||||
* Account id
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Account secret key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $secret;
|
||||
|
||||
/**
|
||||
* Basename of plugin
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Whether admin accepted opt in
|
||||
* terms and permissions
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInstalled = false;
|
||||
|
||||
/**
|
||||
* Is user sign in for data tracking
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isOptedIn = false;
|
||||
|
||||
/**
|
||||
* Is user accepted permissions grant
|
||||
* for collection site data
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isSigned = false;
|
||||
|
||||
/**
|
||||
* Is user ever resolved install modal window?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInstallResolved;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
* @return AccountData
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isInstalled()
|
||||
{
|
||||
return $this->isInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isInstalled
|
||||
*/
|
||||
public function setIsInstalled($isInstalled)
|
||||
{
|
||||
$this->isInstalled = $isInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isOptedIn()
|
||||
{
|
||||
return $this->isOptedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isOptedIn
|
||||
*/
|
||||
public function setIsOptedIn($isOptedIn)
|
||||
{
|
||||
$this->isOptedIn = $isOptedIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSigned()
|
||||
{
|
||||
return $this->isSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isSigned
|
||||
*/
|
||||
public function setIsSigned($isSigned)
|
||||
{
|
||||
$this->isSigned = $isSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSecret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $secret
|
||||
*/
|
||||
public function setSecret($secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isInstallResolved()
|
||||
{
|
||||
return $this->isInstallResolved;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isInstallResolved
|
||||
*/
|
||||
public function setIsInstallResolved($isInstallResolved)
|
||||
{
|
||||
$this->isInstallResolved = $isInstallResolved;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Account;
|
||||
|
||||
|
||||
use Analyst\Core\AbstractFactory;
|
||||
|
||||
/**
|
||||
* Class AccountDataFactory
|
||||
*
|
||||
* Holds information about this
|
||||
* wordpress project plugins accounts
|
||||
*
|
||||
*/
|
||||
class AccountDataFactory extends AbstractFactory
|
||||
{
|
||||
private static $instance;
|
||||
|
||||
CONST OPTIONS_KEY = 'analyst_accounts_data';
|
||||
|
||||
/**
|
||||
* @var AccountData[]
|
||||
*/
|
||||
protected $accounts = [];
|
||||
|
||||
/**
|
||||
* Read factory from options or make fresh instance
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (!static::$instance) {
|
||||
$raw = get_option(self::OPTIONS_KEY);
|
||||
|
||||
// In case object is already unserialized
|
||||
// and instance of AccountDataFactory we
|
||||
// return it, in other case deal with
|
||||
// serialized string data
|
||||
if ($raw instanceof self) {
|
||||
static::$instance = $raw;
|
||||
} else {
|
||||
static::$instance = is_string($raw) ? static::unserialize($raw) : new self();
|
||||
}
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync this object data with cache
|
||||
*/
|
||||
public function sync()
|
||||
{
|
||||
update_option(self::OPTIONS_KEY, serialize($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync this instance data with cache
|
||||
*/
|
||||
public static function syncData()
|
||||
{
|
||||
static::instance()->sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find plugin account data or create fresh one
|
||||
*
|
||||
* @param Account $account
|
||||
* @return AccountData|null
|
||||
*/
|
||||
public function resolvePluginAccountData(Account $account)
|
||||
{
|
||||
$accountData = $this->findAccountDataById($account->getId());
|
||||
|
||||
if (!$accountData) {
|
||||
$accountData = new AccountData();
|
||||
|
||||
// Set proper default values
|
||||
$accountData->setPath($account->getPath());
|
||||
$accountData->setId($account->getId());
|
||||
$accountData->setSecret($account->getClientSecret());
|
||||
|
||||
array_push($this->accounts, $accountData);
|
||||
}
|
||||
|
||||
return $accountData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should return account data by base path
|
||||
*
|
||||
* @param $basePath
|
||||
* @return AccountData
|
||||
*/
|
||||
public function getAccountDataByBasePath($basePath)
|
||||
{
|
||||
foreach ($this->accounts as $iterable) {
|
||||
$iterableBasePath = plugin_basename($iterable->getPath());
|
||||
|
||||
if ($iterableBasePath === $basePath) {
|
||||
return $iterable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return account by id
|
||||
*
|
||||
* @param $id
|
||||
* @return AccountData|null
|
||||
*/
|
||||
private function findAccountDataById($id)
|
||||
{
|
||||
foreach ($this->accounts as &$iterable) {
|
||||
if ($iterable->getId() === $id) {
|
||||
return $iterable;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
167
wp-content/plugins/copy-delete-posts/analyst/src/Analyst.php
Normal file
167
wp-content/plugins/copy-delete-posts/analyst/src/Analyst.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
namespace Analyst;
|
||||
|
||||
use Account\Account;
|
||||
use Account\AccountDataFactory;
|
||||
use Analyst\Contracts\AnalystContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
class Analyst implements AnalystContract
|
||||
{
|
||||
/**
|
||||
* All plugin's accounts
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $accounts = array();
|
||||
|
||||
/**
|
||||
* @var Mutator
|
||||
*/
|
||||
protected $mutator;
|
||||
|
||||
/**
|
||||
* @var AccountDataFactory
|
||||
*/
|
||||
protected $accountDataFactory;
|
||||
|
||||
/**
|
||||
* Base url to api
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $apiBase = 'https://feedback.sellcodes.com/api/v1';
|
||||
|
||||
/**
|
||||
* @var Collector
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
*
|
||||
* @var static
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* Get instance of analyst
|
||||
*
|
||||
* @return Analyst
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (!static::$instance) {
|
||||
static::$instance = new Analyst();
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
protected function __construct()
|
||||
{
|
||||
$this->mutator = new Mutator();
|
||||
|
||||
$this->accountDataFactory = AccountDataFactory::instance();
|
||||
|
||||
$this->mutator->initialize();
|
||||
|
||||
$this->collector = new Collector($this);
|
||||
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize rest of application
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
add_action('init', function () {
|
||||
$this->collector->loadCurrentUser();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new account
|
||||
*
|
||||
* @param Account $account
|
||||
* @return Analyst
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function registerAccount($account)
|
||||
{
|
||||
// Stop propagation when account is already registered
|
||||
if ($this->isAccountRegistered($account)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Resolve account data from factory
|
||||
$accountData = $this->accountDataFactory->resolvePluginAccountData($account);
|
||||
|
||||
$account->setData($accountData);
|
||||
|
||||
$account->setRequestor(
|
||||
$this->resolveRequestorForAccount($account)
|
||||
);
|
||||
|
||||
$account->setCollector($this->collector);
|
||||
|
||||
$account->registerHooks();
|
||||
|
||||
$this->accounts[$account->getId()] = $account;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must return version of analyst
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function version()
|
||||
{
|
||||
$version = require __DIR__ . '/../version.php';
|
||||
|
||||
return $version['sdk'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this account registered
|
||||
*
|
||||
* @param Account $account
|
||||
* @return bool
|
||||
*/
|
||||
protected function isAccountRegistered($account)
|
||||
{
|
||||
return isset($this->accounts[$account->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves requestor for account
|
||||
*
|
||||
* @param Account $account
|
||||
* @return RequestorContract
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function resolveRequestorForAccount(Account $account)
|
||||
{
|
||||
$requestor = new ApiRequestor($account->getId(), $account->getClientSecret(), $this->apiBase);
|
||||
|
||||
// Set SDK version
|
||||
$requestor->setDefaultHeader(
|
||||
'x-analyst-client-user-agent',
|
||||
sprintf('Analyst/%s', $this->version())
|
||||
);
|
||||
|
||||
return $requestor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getApiBase()
|
||||
{
|
||||
return $this->apiBase;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst;
|
||||
|
||||
use Exception;
|
||||
use Analyst\Contracts\HttpClientContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
class ApiRequestor implements RequestorContract
|
||||
{
|
||||
/**
|
||||
* Supported http client
|
||||
*
|
||||
* @var HttpClientContract
|
||||
*/
|
||||
protected $httpClient;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $clientId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $clientSecret;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $apiBase;
|
||||
|
||||
/**
|
||||
* Default headers to be sent
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultHeaders = [
|
||||
'accept' => 'application/json',
|
||||
'content-type' => 'application/json'
|
||||
];
|
||||
|
||||
/**
|
||||
* Prioritized http clients
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $availableClients = [
|
||||
'Analyst\Http\WordPressHttpClient',
|
||||
'Analyst\Http\CurlHttpClient',
|
||||
'Analyst\Http\DummyHttpClient',
|
||||
];
|
||||
|
||||
/**
|
||||
* ApiRequestor constructor.
|
||||
* @param $id
|
||||
* @param $secret
|
||||
* @param $apiBase
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($id, $secret, $apiBase)
|
||||
{
|
||||
$this->clientId = $id;
|
||||
$this->clientSecret = $secret;
|
||||
|
||||
$this->setApiBase($apiBase);
|
||||
|
||||
$this->httpClient = $this->resolveHttpClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set api base url
|
||||
*
|
||||
* @param $url
|
||||
*/
|
||||
public function setApiBase($url)
|
||||
{
|
||||
$this->apiBase = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request
|
||||
*
|
||||
* @param $url
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($url, $headers = [])
|
||||
{
|
||||
return $this->request('GET', $url, null, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post request
|
||||
*
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function post($url, $body = [], $headers = [])
|
||||
{
|
||||
return $this->request('POST', $url, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put request
|
||||
*
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function put($url, $body = [], $headers = [])
|
||||
{
|
||||
return $this->request('PUT', $url, $body, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete request
|
||||
*
|
||||
* @param $url
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete($url, $headers = [])
|
||||
{
|
||||
return $this->request('DELETE', $url, null, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request to api
|
||||
*
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param array $body
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
protected function request($method, $url, $body = [], $headers = [])
|
||||
{
|
||||
$fullUrl = $this->resolveFullUrl($url);
|
||||
|
||||
$date = date('r', time());
|
||||
|
||||
$headers['date'] = $date;
|
||||
$headers['signature'] = $this->resolveSignature($this->clientSecret, $method, $fullUrl, $body, $date);
|
||||
|
||||
// Lowercase header names
|
||||
$headers = $this->prepareHeaders(
|
||||
array_merge($headers, $this->defaultHeaders)
|
||||
);
|
||||
|
||||
$response = $this->httpClient->request($method, $fullUrl, $body, $headers);
|
||||
|
||||
// TODO: Check response code and take actions
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one default header
|
||||
*
|
||||
* @param $header
|
||||
* @param $value
|
||||
*/
|
||||
public function setDefaultHeader($header, $value)
|
||||
{
|
||||
$this->defaultHeaders[
|
||||
$this->resolveValidHeaderName($header)
|
||||
] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves supported http client
|
||||
*
|
||||
* @return HttpClientContract
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function resolveHttpClient()
|
||||
{
|
||||
$clients = array_filter($this->availableClients, $this->guessClientSupportEnvironment());
|
||||
|
||||
if (!isset($clients[0])) {
|
||||
throw new Exception('There is no http client which this application can support');
|
||||
}
|
||||
|
||||
// Instantiate first supported http client
|
||||
return new $clients[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* This will filter out clients which is not supported
|
||||
* by the current environment
|
||||
*
|
||||
* @return \Closure
|
||||
*/
|
||||
protected function guessClientSupportEnvironment()
|
||||
{
|
||||
return function ($client) {
|
||||
return forward_static_call([$client, 'hasSupport']);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves valid header name
|
||||
*
|
||||
* @param $headerName
|
||||
* @return string
|
||||
*/
|
||||
private function resolveValidHeaderName($headerName)
|
||||
{
|
||||
return strtolower($headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lowercase header names
|
||||
*
|
||||
* @param $headers
|
||||
* @return array
|
||||
*/
|
||||
private function prepareHeaders($headers)
|
||||
{
|
||||
return array_change_key_case($headers, CASE_LOWER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign request
|
||||
*
|
||||
* @param $key
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param $date
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
private function resolveSignature($key, $method, $url, $body, $date)
|
||||
{
|
||||
$string = implode('\n', [$method, $url, md5(json_encode($body)), $date]);
|
||||
|
||||
$contentSecret = hash_hmac('sha256', $string, $key);
|
||||
|
||||
return sprintf('%s:%s', $this->clientId, $contentSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose full url
|
||||
*
|
||||
* @param $url
|
||||
* @return string
|
||||
*/
|
||||
private function resolveFullUrl($url)
|
||||
{
|
||||
return sprintf('%s/%s', $this->apiBase, trim($url, '/'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst;
|
||||
|
||||
class ApiResponse
|
||||
{
|
||||
/**
|
||||
* Response headers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $headers;
|
||||
|
||||
/**
|
||||
* Response body
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $body;
|
||||
|
||||
/**
|
||||
* Status code
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $code;
|
||||
|
||||
public function __construct($body, $code, $headers)
|
||||
{
|
||||
$this->body = $body;
|
||||
$this->code = $code;
|
||||
$this->headers = $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether status code is successful
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSuccess()
|
||||
{
|
||||
return $this->code >= 200 && $this->code < 300;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Cache;
|
||||
|
||||
use Analyst\Contracts\CacheContract;
|
||||
|
||||
/**
|
||||
* Class DatabaseCache
|
||||
*
|
||||
* @since 1.1.5
|
||||
*/
|
||||
class DatabaseCache implements CacheContract
|
||||
{
|
||||
const OPTION_KEY = 'analyst_cache';
|
||||
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* Get instance of db cache
|
||||
*
|
||||
* @return DatabaseCache
|
||||
*/
|
||||
public static function getInstance()
|
||||
{
|
||||
if (!self::$instance) {
|
||||
self::$instance = new DatabaseCache();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key value pair
|
||||
*
|
||||
* @var array[]
|
||||
*/
|
||||
protected $values = [];
|
||||
|
||||
/**
|
||||
* DatabaseCache constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$raw = get_option(self::OPTION_KEY, serialize([]));
|
||||
|
||||
// Raw data may be an array already
|
||||
$this->values = is_array($raw) ? $raw : @unserialize($raw);
|
||||
|
||||
// In case serialization is failed
|
||||
// make sure values is an array
|
||||
if (!is_array($this->values)) {
|
||||
$this->values = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save value with given key
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function put($key, $value)
|
||||
{
|
||||
$this->values[$key] = $value;
|
||||
|
||||
$this->sync();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get value by given key
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @param null $default
|
||||
* @return string
|
||||
*/
|
||||
public function get($key, $default = null)
|
||||
{
|
||||
$value = isset($this->values[$key]) ? $this->values[$key] : $default;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function delete($key)
|
||||
{
|
||||
if (isset($this->values[$key])) {
|
||||
unset($this->values[$key]);
|
||||
|
||||
$this->sync();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cache in DB
|
||||
*/
|
||||
protected function sync()
|
||||
{
|
||||
update_option(self::OPTION_KEY, serialize($this->values));
|
||||
}
|
||||
|
||||
/**
|
||||
* Should get value and remove it from cache
|
||||
*
|
||||
* @param $key
|
||||
* @param null $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function pop($key, $default = null)
|
||||
{
|
||||
$value = $this->get($key);
|
||||
|
||||
$this->delete($key);
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
221
wp-content/plugins/copy-delete-posts/analyst/src/Collector.php
Normal file
221
wp-content/plugins/copy-delete-posts/analyst/src/Collector.php
Normal file
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst;
|
||||
|
||||
use Analyst\Contracts\AnalystContract;
|
||||
|
||||
/**
|
||||
* Class Collector is a set of getters
|
||||
* to retrieve some data from wp site
|
||||
*/
|
||||
class Collector
|
||||
{
|
||||
/**
|
||||
* @var AnalystContract
|
||||
*/
|
||||
protected $sdk;
|
||||
|
||||
/**
|
||||
* @var \WP_User
|
||||
*/
|
||||
protected $user;
|
||||
|
||||
public function __construct(AnalystContract $sdk)
|
||||
{
|
||||
$this->sdk = $sdk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load current user into memory
|
||||
*/
|
||||
public function loadCurrentUser()
|
||||
{
|
||||
$this->user = wp_get_current_user();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get site url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSiteUrl()
|
||||
{
|
||||
return get_option('siteurl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user email
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrentUserEmail()
|
||||
{
|
||||
return $this->user->user_email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get's email from general settings
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getGeneralEmailAddress()
|
||||
{
|
||||
return get_option('admin_email');
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this user administrator
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isUserAdministrator()
|
||||
{
|
||||
return in_array('administrator', $this->user->roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* User name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrentUserName()
|
||||
{
|
||||
return $this->user ? $this->user->user_nicename : 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* WP version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getWordPressVersion()
|
||||
{
|
||||
global $wp_version;
|
||||
|
||||
return $wp_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* PHP version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPHPVersion()
|
||||
{
|
||||
return phpversion();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves plugin information
|
||||
*
|
||||
* @param string $path Absolute path to plugin
|
||||
* @return array
|
||||
*/
|
||||
public function resolvePluginData($path)
|
||||
{
|
||||
if( !function_exists('get_plugin_data') ){
|
||||
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
|
||||
}
|
||||
|
||||
return get_plugin_data($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin name by path
|
||||
*
|
||||
* @param $path
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginName($path)
|
||||
{
|
||||
$data = $this->resolvePluginData($path);
|
||||
|
||||
return $data['Name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin version
|
||||
*
|
||||
* @param $path
|
||||
* @return string
|
||||
*/
|
||||
public function getPluginVersion($path)
|
||||
{
|
||||
$data = $this->resolvePluginData($path);
|
||||
|
||||
return $data['Version'] ? $data['Version'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server ip
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getServerIp()
|
||||
{
|
||||
return sanitize_text_field($_SERVER['SERVER_ADDR']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSDKVersion()
|
||||
{
|
||||
return $this->sdk->version();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getMysqlVersion()
|
||||
{
|
||||
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
|
||||
|
||||
if ($conn) {
|
||||
$version = mysqli_get_server_info($conn);
|
||||
} else {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
return $version ? $version : 'unknown';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getSiteLanguage()
|
||||
{
|
||||
return get_locale();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Current WP theme
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public function getCurrentThemeName()
|
||||
{
|
||||
return wp_get_theme()->get('Name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active plugins list
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getActivePluginsList()
|
||||
{
|
||||
if (!function_exists('get_plugins')) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$allPlugins = get_plugins();
|
||||
|
||||
$activePluginsNames = array_map(function ($path) use ($allPlugins) {
|
||||
return $allPlugins[$path]['Name'];
|
||||
}, get_option('active_plugins'));
|
||||
|
||||
return $activePluginsNames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Analyst\Contracts;
|
||||
|
||||
interface AnalystContract
|
||||
{
|
||||
/**
|
||||
* Must return version of analyst
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function version();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Contracts;
|
||||
|
||||
/**
|
||||
* Interface CacheContract
|
||||
*
|
||||
* @since 1.1.5
|
||||
*/
|
||||
interface CacheContract
|
||||
{
|
||||
/**
|
||||
* Save value with given key
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function put($key, $value);
|
||||
|
||||
/**
|
||||
* Get value by given key
|
||||
*
|
||||
* @param $key
|
||||
*
|
||||
* @param null $default
|
||||
* @return string
|
||||
*/
|
||||
public function get($key, $default = null);
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function delete($key);
|
||||
|
||||
/**
|
||||
* Should get value and remove it from cache
|
||||
*
|
||||
* @param $key
|
||||
* @param null $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function pop($key, $default = null);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace Analyst\Contracts;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
|
||||
interface HttpClientContract
|
||||
{
|
||||
/**
|
||||
* Make an http request
|
||||
*
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param $headers
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function request($method, $url, $body, $headers);
|
||||
|
||||
/**
|
||||
* Must return `true` if client is supported
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasSupport();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Contracts;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
|
||||
interface RequestContract
|
||||
{
|
||||
/**
|
||||
* Cast request data to array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Contracts;
|
||||
|
||||
interface RequestorContract
|
||||
{
|
||||
/**
|
||||
* Get request
|
||||
*
|
||||
* @param $url
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($url, $headers = []);
|
||||
|
||||
/**
|
||||
* Post request
|
||||
*
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function post($url, $body = [], $headers = []);
|
||||
|
||||
/**
|
||||
* Put request
|
||||
*
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function put($url, $body = [], $headers = []);
|
||||
|
||||
/**
|
||||
* Delete request
|
||||
*
|
||||
* @param $url
|
||||
* @param array $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function delete($url, $headers = []);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Contracts;
|
||||
|
||||
interface TrackerContract
|
||||
{
|
||||
/**
|
||||
* Should register activation and deactivation
|
||||
* event hooks
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerHooks();
|
||||
|
||||
/**
|
||||
* Will fire when admin activates plugin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onActivePluginListener();
|
||||
|
||||
/**
|
||||
* Will fire when admin deactivates plugin
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onDeactivatePluginListener();
|
||||
|
||||
/**
|
||||
* Will fire when user opted in
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onOptInListener();
|
||||
|
||||
/**
|
||||
* Will fire when user opted out
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onOptOutListener();
|
||||
|
||||
/**
|
||||
* Will fire when user accept opt/in at first time
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onInstallListener();
|
||||
|
||||
/**
|
||||
* Will fire when user skipped installation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onSkipInstallListener();
|
||||
|
||||
/**
|
||||
* Will fire when user delete plugin through admin panel.
|
||||
* This action will happen if admin at least once
|
||||
* activated the plugin.
|
||||
*
|
||||
* The register_uninstall_hook function accepts only static
|
||||
* function or global function to be executed, so this is
|
||||
* why this method is static
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function onUninstallPluginListener();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Core;
|
||||
|
||||
abstract class AbstractFactory
|
||||
{
|
||||
/**
|
||||
* Unserialize to static::class instance
|
||||
*
|
||||
* @param $raw
|
||||
* @return static
|
||||
*/
|
||||
protected static function unserialize($raw)
|
||||
{
|
||||
$instance = maybe_unserialize($raw);
|
||||
|
||||
$isProperObject = is_object($instance) && $instance instanceof static;
|
||||
|
||||
// In case for some reason unserialized object is not
|
||||
// static::class we make sure it is static::class
|
||||
if (!$isProperObject) {
|
||||
$instance = new static();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Contracts\HttpClientContract;
|
||||
|
||||
class CurlHttpClient implements HttpClientContract
|
||||
{
|
||||
/**
|
||||
* Make an http request
|
||||
*
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param array $body
|
||||
* @param $headers
|
||||
* @return mixed
|
||||
*/
|
||||
public function request($method, $url, $body, $headers)
|
||||
{
|
||||
$method = strtoupper($method);
|
||||
|
||||
$options = [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_HTTPHEADER => $this->prepareRequestHeaders($headers),
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
];
|
||||
|
||||
if ($method === 'POST') {
|
||||
$options[CURLOPT_POST] = 1;
|
||||
$options[CURLOPT_POSTFIELDS] = json_encode($body);
|
||||
}
|
||||
|
||||
$curl = curl_init();
|
||||
|
||||
curl_setopt_array($curl, $options);
|
||||
|
||||
$response = curl_exec($curl);
|
||||
|
||||
list($rawHeaders, $rawBody) = explode("\r\n\r\n", $response, 2);
|
||||
|
||||
$info = curl_getinfo($curl);
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
$responseHeaders = $this->resolveResponseHeaders($rawHeaders);
|
||||
$responseBody = json_decode($rawBody, true);
|
||||
|
||||
return new ApiResponse($responseBody, $info['http_code'], $responseHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must return `true` if client is supported
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasSupport()
|
||||
{
|
||||
return function_exists('curl_version');
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify request headers from key value pair
|
||||
* to vector array
|
||||
*
|
||||
* @param array $headers
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareRequestHeaders ($headers)
|
||||
{
|
||||
return array_map(function ($key, $value) {
|
||||
return sprintf('%s:%s', $key, $value);
|
||||
}, array_keys($headers), $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve raw response headers as
|
||||
* associative array
|
||||
*
|
||||
* @param $rawHeaders
|
||||
* @return array
|
||||
*/
|
||||
private function resolveResponseHeaders($rawHeaders)
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach (explode("\r\n", $rawHeaders) as $i => $line) {
|
||||
$parts = explode(': ', $line);
|
||||
|
||||
if (count($parts) === 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$headers[$parts[0]] = $parts[1];
|
||||
}
|
||||
return $headers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Contracts\HttpClientContract;
|
||||
|
||||
class DummyHttpClient implements HttpClientContract
|
||||
{
|
||||
/**
|
||||
* Make an http request
|
||||
*
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param $headers
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function request($method, $url, $body, $headers)
|
||||
{
|
||||
return new ApiResponse('Dummy response', 200, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must return `true` if client is supported
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasSupport()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
abstract class AbstractLoggerRequest implements RequestContract
|
||||
{
|
||||
/**
|
||||
* @var Collector
|
||||
*/
|
||||
protected $collector;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
public function __construct(Collector $collector, $pluginId, $path)
|
||||
{
|
||||
$this->collector = $collector;
|
||||
$this->id = $pluginId;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cast request data to array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'plugin_id' => $this->id,
|
||||
'php_version' => $this->collector->getPHPVersion(),
|
||||
'wp_version' => $this->collector->getWordPressVersion(),
|
||||
'plugin_version' => $this->collector->getPluginVersion($this->path),
|
||||
'url' => $this->collector->getSiteUrl(),
|
||||
'sdk_version' => $this->collector->getSDKVersion(),
|
||||
'ip' => $this->collector->getServerIp(),
|
||||
'mysql_version' => $this->collector->getMysqlVersion(),
|
||||
'locale' => $this->collector->getSiteLanguage(),
|
||||
'current_theme' => $this->collector->getCurrentThemeName(),
|
||||
'active_plugins_list' => implode(', ', $this->collector->getActivePluginsList()),
|
||||
'email' => $this->collector->getGeneralEmailAddress(),
|
||||
'name' => $this->collector->getCurrentUserName()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public abstract function execute(RequestorContract $requestor);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class ActivateRequest
|
||||
*
|
||||
* Is is very similar to install request
|
||||
* but with different path
|
||||
*
|
||||
* @since 0.9.12
|
||||
*/
|
||||
class ActivateRequest extends AbstractLoggerRequest
|
||||
{
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor)
|
||||
{
|
||||
return $requestor->post('logger/activate', $this->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request instance
|
||||
*
|
||||
* @param Collector $collector
|
||||
* @param $pluginId
|
||||
* @param $path
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Collector $collector, $pluginId, $path)
|
||||
{
|
||||
return new static($collector, $pluginId, $path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class DeactivateRequest
|
||||
*
|
||||
* @since 0.9.10
|
||||
*/
|
||||
class DeactivateRequest extends AbstractLoggerRequest
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $question;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $answer;
|
||||
|
||||
/**
|
||||
* @param Collector $collector
|
||||
* @param $pluginId
|
||||
* @param $path
|
||||
* @param $question
|
||||
* @param $answer
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Collector $collector, $pluginId, $path, $question, $answer)
|
||||
{
|
||||
return new static($collector, $pluginId, $path, $question, $answer);
|
||||
}
|
||||
|
||||
public function __construct(Collector $collector, $pluginId, $path, $question, $answer)
|
||||
{
|
||||
parent::__construct($collector, $pluginId, $path);
|
||||
|
||||
$this->question = $question;
|
||||
$this->answer = $answer;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return array_merge(parent::toArray(), [
|
||||
'question' => $this->question,
|
||||
'answer' => $this->answer,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor)
|
||||
{
|
||||
return $requestor->post('logger/deactivate', $this->toArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class InstallRequest
|
||||
*
|
||||
* @since 0.9.4
|
||||
*/
|
||||
class InstallRequest extends AbstractLoggerRequest
|
||||
{
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor)
|
||||
{
|
||||
return $requestor->post('logger/install', $this->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request instance
|
||||
*
|
||||
* @param Collector $collector
|
||||
* @param $pluginId
|
||||
* @param $path
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Collector $collector, $pluginId, $path)
|
||||
{
|
||||
return new static($collector, $pluginId, $path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class OptInRequest
|
||||
*
|
||||
* Is is very similar to install request
|
||||
* but with different path
|
||||
*
|
||||
* @since 0.9.5
|
||||
*/
|
||||
class OptInRequest extends AbstractLoggerRequest
|
||||
{
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor)
|
||||
{
|
||||
return $requestor->post('logger/opt-in', $this->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request instance
|
||||
*
|
||||
* @param Collector $collector
|
||||
* @param $pluginId
|
||||
* @param $path
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Collector $collector, $pluginId, $path)
|
||||
{
|
||||
return new static($collector, $pluginId, $path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestContract;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class OptOutRequest
|
||||
*
|
||||
* Is is very similar to install request
|
||||
* but with different path
|
||||
*
|
||||
* @since 0.9.9
|
||||
*/
|
||||
class OptOutRequest extends AbstractLoggerRequest
|
||||
{
|
||||
/**
|
||||
* @param Collector $collector
|
||||
* @param $pluginId
|
||||
* @param $path
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Collector $collector, $pluginId, $path)
|
||||
{
|
||||
return new static($collector, $pluginId, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor)
|
||||
{
|
||||
return $requestor->post('logger/opt-out', $this->toArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http\Requests;
|
||||
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Collector;
|
||||
use Analyst\Contracts\RequestorContract;
|
||||
|
||||
/**
|
||||
* Class DeactivateRequest
|
||||
*
|
||||
* @since 0.9.13
|
||||
*/
|
||||
class UninstallRequest extends AbstractLoggerRequest
|
||||
{
|
||||
/**
|
||||
* @param Collector $collector
|
||||
* @param $pluginId
|
||||
* @param $path
|
||||
* @return static
|
||||
*/
|
||||
public static function make(Collector $collector, $pluginId, $path)
|
||||
{
|
||||
return new static($collector, $pluginId, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the request
|
||||
* @param RequestorContract $requestor
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function execute(RequestorContract $requestor)
|
||||
{
|
||||
return $requestor->post('logger/uninstall', $this->toArray());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Http;
|
||||
|
||||
use WP_Error;
|
||||
use Analyst\ApiResponse;
|
||||
use Analyst\Contracts\HttpClientContract;
|
||||
use Requests_Utility_CaseInsensitiveDictionary;
|
||||
|
||||
class WordPressHttpClient implements HttpClientContract
|
||||
{
|
||||
/**
|
||||
* Make an http request
|
||||
*
|
||||
* @param $method
|
||||
* @param $url
|
||||
* @param $body
|
||||
* @param $headers
|
||||
* @return ApiResponse
|
||||
*/
|
||||
public function request($method, $url, $body, $headers)
|
||||
{
|
||||
$options = [
|
||||
'body' => json_encode($body),
|
||||
'headers' => $headers,
|
||||
'method' => $method,
|
||||
'timeout' => 30,
|
||||
];
|
||||
|
||||
$response = wp_remote_request($url, $options);
|
||||
|
||||
$body = [];
|
||||
$responseHeaders = [];
|
||||
|
||||
if ($response instanceof WP_Error) {
|
||||
$code = $response->get_error_code();
|
||||
} else {
|
||||
/** @var Requests_Utility_CaseInsensitiveDictionary $headers */
|
||||
$responseHeaders = $response['headers']->getAll();
|
||||
$body = json_decode($response['body'], true);
|
||||
$code = $response['response']['code'];
|
||||
}
|
||||
|
||||
|
||||
return new ApiResponse(
|
||||
$body,
|
||||
$code,
|
||||
$responseHeaders
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must return `true` if client is supported
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasSupport()
|
||||
{
|
||||
return function_exists('wp_remote_request');
|
||||
}
|
||||
}
|
||||
135
wp-content/plugins/copy-delete-posts/analyst/src/Mutator.php
Normal file
135
wp-content/plugins/copy-delete-posts/analyst/src/Mutator.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst;
|
||||
|
||||
use Analyst\Cache\DatabaseCache;
|
||||
use Analyst\Contracts\CacheContract;
|
||||
use Analyst\Notices\NoticeFactory;
|
||||
|
||||
/**
|
||||
* Class Mutator mutates (modifies) UX with additional
|
||||
* functional
|
||||
*/
|
||||
class Mutator
|
||||
{
|
||||
protected $notices = [];
|
||||
|
||||
/**
|
||||
* @var NoticeFactory
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
/**
|
||||
* @var CacheContract
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->factory = NoticeFactory::instance();
|
||||
|
||||
$this->notices = $this->factory->getNotices();
|
||||
|
||||
$this->cache = DatabaseCache::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register filters all necessary stuff.
|
||||
* Can be invoked only once.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
$this->registerLinks();
|
||||
$this->registerAssets();
|
||||
$this->registerHooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all necessary filters and templates
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerLinks()
|
||||
{
|
||||
add_action('admin_footer', function () {
|
||||
analyst_require_template('optout.php', [
|
||||
'shieldImage' => analyst_assets_url('img/shield_question.png')
|
||||
]);
|
||||
|
||||
analyst_require_template('optin.php');
|
||||
|
||||
analyst_require_template('forms/deactivate.php', [
|
||||
'pencilImage' => analyst_assets_url('img/pencil.png'),
|
||||
'smileImage' => analyst_assets_url('img/smile.png'),
|
||||
]);
|
||||
|
||||
analyst_require_template('forms/install.php', [
|
||||
'pluginToInstall' => $this->cache->get('plugin_to_install'),
|
||||
'shieldImage' => analyst_assets_url('img/shield_success.png'),
|
||||
]);
|
||||
});
|
||||
|
||||
add_action('admin_notices',function () {
|
||||
foreach ($this->notices as $notice) {
|
||||
analyst_require_template('notice.php', ['notice' => $notice]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all assets
|
||||
*/
|
||||
public function registerAssets()
|
||||
{
|
||||
add_action('admin_enqueue_scripts', function () {
|
||||
wp_enqueue_style('analyst_custom', analyst_assets_url('/css/customize.css'));
|
||||
wp_enqueue_script('analyst_custom', analyst_assets_url('/js/customize.js'));
|
||||
wp_localize_script('analyst_custom', 'analyst_opt_localize', array(
|
||||
'nonce' => wp_create_nonce('analyst_opt_ajax_nonce')
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register action hooks
|
||||
*/
|
||||
public function registerHooks()
|
||||
{
|
||||
add_action('wp_ajax_analyst_notification_dismiss', function () {
|
||||
$capabilities = [
|
||||
'activate_plugins',
|
||||
'edit_plugins',
|
||||
'install_plugins',
|
||||
'update_plugins',
|
||||
'delete_plugins',
|
||||
'manage_network_plugins',
|
||||
'upload_plugins'
|
||||
];
|
||||
|
||||
// Allow if has any of above permissions
|
||||
$hasPerms = false;
|
||||
foreach ($capabilities as $i => $cap) {
|
||||
if (current_user_can($cap)) {
|
||||
$hasPerms = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasPerms == false) {
|
||||
wp_send_json_error(['message' => 'no_permissions']);
|
||||
die;
|
||||
}
|
||||
|
||||
if (!isset($_POST['nonce']) || !wp_verify_nonce(sanitize_text_field($_POST['nonce']), 'analyst_opt_ajax_nonce')) {
|
||||
wp_send_json_error(['message' => 'invalid_nonce']);
|
||||
die;
|
||||
}
|
||||
|
||||
$this->factory->remove(sanitize_text_field($_POST['id']));
|
||||
|
||||
$this->factory->sync();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Notices;
|
||||
|
||||
class Notice
|
||||
{
|
||||
/**
|
||||
* Id of notice
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* Body of notice
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $body;
|
||||
|
||||
/**
|
||||
* Account id
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $accountId;
|
||||
|
||||
/**
|
||||
* The plugin name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $pluginName;
|
||||
|
||||
/**
|
||||
* New notice
|
||||
*
|
||||
* @param $id
|
||||
* @param $accountId
|
||||
* @param $body
|
||||
* @param null $pluginName
|
||||
*
|
||||
* @return Notice
|
||||
*/
|
||||
public static function make($id, $accountId, $body, $pluginName = null)
|
||||
{
|
||||
return new Notice($id, $accountId, $body, $pluginName);
|
||||
}
|
||||
|
||||
public function __construct($id, $accountId, $body, $pluginName)
|
||||
{
|
||||
$this->setId($id);
|
||||
$this->setBody($body);
|
||||
$this->setAccountId($accountId);
|
||||
$this->setPluginName($pluginName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
*/
|
||||
public function setId($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBody()
|
||||
{
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $body
|
||||
*/
|
||||
public function setBody($body)
|
||||
{
|
||||
$this->body = $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAccountId()
|
||||
{
|
||||
return $this->accountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $accountId
|
||||
*/
|
||||
public function setAccountId($accountId)
|
||||
{
|
||||
$this->accountId = $accountId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getPluginName()
|
||||
{
|
||||
return $this->pluginName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pluginName
|
||||
*/
|
||||
public function setPluginName($pluginName)
|
||||
{
|
||||
$this->pluginName = $pluginName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace Analyst\Notices;
|
||||
|
||||
use Analyst\Core\AbstractFactory;
|
||||
|
||||
class NoticeFactory extends AbstractFactory
|
||||
{
|
||||
private static $instance;
|
||||
|
||||
CONST OPTIONS_KEY = 'analyst_notices';
|
||||
|
||||
/**
|
||||
* Application notifications
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $notices = [];
|
||||
|
||||
/**
|
||||
* Read factory from options or make fresh instance
|
||||
*
|
||||
* @return NoticeFactory
|
||||
*/
|
||||
public static function instance()
|
||||
{
|
||||
if (!static::$instance) {
|
||||
$raw = get_option(self::OPTIONS_KEY);
|
||||
|
||||
// In case object is already unserialized
|
||||
// and instance of AccountDataFactory we
|
||||
// return it, in other case deal with
|
||||
// serialized string data
|
||||
if ($raw instanceof self) {
|
||||
static::$instance = $raw;
|
||||
} else {
|
||||
static::$instance = is_string($raw) ? static::unserialize($raw) : new self();
|
||||
}
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync this object data with cache
|
||||
*/
|
||||
public function sync()
|
||||
{
|
||||
update_option(self::OPTIONS_KEY, serialize($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync this instance data with cache
|
||||
*/
|
||||
public static function syncData()
|
||||
{
|
||||
static::instance()->sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getNotices()
|
||||
{
|
||||
return $this->notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out notices for certain account
|
||||
*
|
||||
* @param $accountId
|
||||
* @return array
|
||||
*/
|
||||
public function getNoticesForAccount($accountId)
|
||||
{
|
||||
return array_filter($this->notices, function (Notice $notice) use ($accountId) {
|
||||
return $notice->getAccountId() === $accountId;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new notice
|
||||
*
|
||||
* @param $notice
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addNotice($notice)
|
||||
{
|
||||
array_push($this->notices, $notice);
|
||||
|
||||
$this->sync();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find notice by id
|
||||
*
|
||||
* @param $id
|
||||
* @return Notice|null
|
||||
*/
|
||||
public function find($id)
|
||||
{
|
||||
$notices = array_filter($this->notices, function (Notice $notice) use ($id) {
|
||||
return $notice->getId() === $id;
|
||||
});
|
||||
|
||||
return array_pop($notices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove notice by it's id
|
||||
*
|
||||
* @param $id
|
||||
*/
|
||||
public function remove($id)
|
||||
{
|
||||
// Get key of notice to remove
|
||||
$key = array_search(
|
||||
$this->find($id),
|
||||
$this->notices
|
||||
);
|
||||
|
||||
// Unset notice with key
|
||||
unset($this->notices[$key]);
|
||||
|
||||
$this->sync();
|
||||
}
|
||||
}
|
||||
73
wp-content/plugins/copy-delete-posts/analyst/src/helpers.php
Normal file
73
wp-content/plugins/copy-delete-posts/analyst/src/helpers.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
if (! function_exists('analyst_assets_path')) {
|
||||
/**
|
||||
* Generates path to file in assets folder
|
||||
*
|
||||
* @param $file
|
||||
* @return string
|
||||
*/
|
||||
function analyst_assets_path($file)
|
||||
{
|
||||
$path = sprintf('%s/assets/%s', realpath(__DIR__ . '/..'), trim($file, '/'));
|
||||
|
||||
return wp_normalize_path($path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (! function_exists('analyst_assets_url')) {
|
||||
/**
|
||||
* Generates url to file in assets folder
|
||||
*
|
||||
* @param $file
|
||||
* @return string
|
||||
*/
|
||||
function analyst_assets_url($file)
|
||||
{
|
||||
$absolutePath = analyst_assets_path($file);
|
||||
|
||||
// We can always rely on WP_PLUGIN_DIR, because that's where
|
||||
// wordpress install it's plugin's. So we remove last segment
|
||||
// of that path to get the content dir AKA directly where
|
||||
// plugins are installed and make the magic...
|
||||
$contentDir = is_link(WP_PLUGIN_DIR) ?
|
||||
dirname(wp_normalize_path(readlink(WP_PLUGIN_DIR))) :
|
||||
dirname(wp_normalize_path(WP_PLUGIN_DIR));
|
||||
|
||||
$relativePath = str_replace( $contentDir, '', $absolutePath);
|
||||
|
||||
return content_url(wp_normalize_path($relativePath));
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('analyst_templates_path')) {
|
||||
/**
|
||||
* Generates path to file in templates folder
|
||||
*
|
||||
* @param $file
|
||||
* @return string
|
||||
*/
|
||||
function analyst_templates_path($file)
|
||||
{
|
||||
$path = sprintf('%s/templates/%s', realpath(__DIR__ . '/..'), trim($file, '/'));
|
||||
|
||||
return wp_normalize_path($path);
|
||||
}
|
||||
}
|
||||
|
||||
if (! function_exists('analyst_require_template')) {
|
||||
/**
|
||||
* Require certain template with data
|
||||
*
|
||||
* @param $file
|
||||
* @param array $data
|
||||
*/
|
||||
function analyst_require_template($file, $data = [])
|
||||
{
|
||||
// Extract data to current scope table
|
||||
extract($data);
|
||||
|
||||
require analyst_templates_path($file);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user