first commit

This commit is contained in:
Roman Pyrih
2026-04-21 15:48:41 +02:00
commit 7483681901
10216 changed files with 3236626 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
<?php
/**
* Google Drive ADDON
*
* Name: Google Drive ADDON
* Version: 1
* Author: Duplicator
* Author URI: https://duplicator.com/
*
* PHP version 5.6
*
* @category Duplicator
* @package Plugin
* @author Duplicator
* @copyright 2011-2021 Snapcreek LLC
* @license https://www.gnu.org/licenses/gpl-3.0.html GPLv3
* @version GIT: $Id$
* @link https://duplicator.com/
*/
namespace Duplicator\Addons\GDriveAddon;
use Duplicator\Addons\GDriveAddon\Models\GDriveStorage;
use Duplicator\Addons\GDriveAddon\Utils\Autoloader;
use Duplicator\Core\Addons\AbstractAddonCore;
use Duplicator\Models\Storages\AbstractStorageEntity;
class GDriveAddon extends AbstractAddonCore
{
const ADDON_PATH = __DIR__;
/**
* @return void
*/
public function init(): void
{
Autoloader::register();
add_action('duplicator_register_storage_types', [$this, 'registerStorages']);
add_filter('duplicator_template_file', [self::class, 'getTemplateFile'], 10, 2);
add_filter('duplicator_usage_stats_storages_infos', [self::class, 'getStorageUsageStats'], 10);
}
/**
* @return void
*/
public function registerStorages(): void
{
GDriveStorage::registerType();
}
/**
* Return template file path
*
* @param string $path path to the template file
* @param string $slugTpl slug of the template
*
* @return string
*/
public static function getTemplateFile($path, $slugTpl)
{
if (strpos($slugTpl, 'gdriveaddon/') === 0) {
return self::getAddonPath() . '/template/' . $slugTpl . '.php';
}
return $path;
}
/**
* Get storage usage stats
*
* @param array<string,int> $storageNums Storages num
*
* @return array<string,int>
*/
public static function getStorageUsageStats($storageNums)
{
if (($storages = AbstractStorageEntity::getAll()) === false) {
$storages = [];
}
$storageNums['storages_gdrive_count'] = 0;
foreach ($storages as $index => $storage) {
if ($storage->getSType() === GDriveStorage::getSType()) {
$storageNums['storages_gdrive_count']++;
}
}
return $storageNums;
}
/**
*
* @return string
*/
public static function getAddonPath(): string
{
return __DIR__;
}
/**
*
* @return string
*/
public static function getAddonFile(): string
{
return __FILE__;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,585 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\GDriveAddon\Models;
use Duplicator\Models\GlobalEntity;
use Duplicator\Utils\Logging\DupLog;
use Duplicator\Core\Views\TplMng;
use Duplicator\Libs\Snap\SnapUtil;
use Duplicator\Models\DynamicGlobalEntity;
use Duplicator\Models\Storages\AbstractStorageEntity;
use Duplicator\Models\Storages\StorageAuthInterface;
use Duplicator\Utils\OAuth\TokenEntity;
use Duplicator\Utils\OAuth\TokenService;
use Duplicator\Views\AdminNotices;
use Exception;
/**
* @property GDriveAdapter $adapter
*/
class GDriveStorage extends AbstractStorageEntity implements StorageAuthInterface
{
// These numbers represent clients created in Google Cloud Console
const GDRIVE_CLIENT_NATIVE = 1; // Native client 1
const GDRIVE_CLIENT_WEB0722 = 2; // Web client 07/2022
const GDRIVE_CLIENT_LATEST = 2; // Latest out of these above
const REQUIRED_SCOPES = [
"openid",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
// The drive.file scope limits access to just those files created by the plugin
"https://www.googleapis.com/auth/drive.file",
];
/**
* Get default config
*
* @return array<string,scalar>
*/
protected static function getDefaultConfig(): array
{
$config = parent::getDefaultConfig();
return array_merge(
$config,
[
'storage_folder_id' => '',
'storage_folder_web_url' => '',
'token_json' => '',
'refresh_token' => '',
'client_number' => -1,
'authorized' => false,
]
);
}
/**
* Get priority, used to sort storages.
* 100 is neutral value, 0 is the highest priority
*
* @return int
*/
public static function getPriority(): int
{
return 300;
}
/**
* Return the storage type
*
* @return int
*/
public static function getSType(): int
{
return 3;
}
/**
* Returns the storage type icon URL
*
* @return string Returns the storage icon URL
*/
public static function getStypeIconURL(): string
{
return DUPLICATOR_IMG_URL . '/google-drive.svg';
}
/**
* Returns the storage type name.
*
* @return string
*/
public static function getStypeName(): string
{
return __('Google Drive', 'duplicator-pro');
}
/**
* Get storage location string
*
* @return string
*/
public function getLocationString(): string
{
if ($this->isAuthorized()) {
return (string) $this->config['storage_folder_web_url'];
} else {
return __('Not Authenticated', 'duplicator-pro');
}
}
/**
* Check if storage is supported
*
* @return bool
*/
public static function isSupported(): bool
{
return (SnapUtil::isCurlEnabled() || SnapUtil::isUrlFopenEnabled());
}
/**
* Get supported notice, displayed if storage isn't supported
*
* @return string html string or empty if storage is supported
*/
public static function getNotSupportedNotice(): string
{
if (static::isSupported()) {
return '';
}
if (!SnapUtil::isCurlEnabled() && !SnapUtil::isUrlFopenEnabled()) {
return esc_html__(
'Google Drive requires either the PHP CURL extension enabled or the allow_url_fopen runtime configuration to be enabled.',
'duplicator-pro'
);
} elseif (!SnapUtil::isCurlEnabled()) {
return esc_html__('Google Drive requires the PHP CURL extension enabled.', 'duplicator-pro');
} else {
return esc_html__('Google Drive requires the allow_url_fopen runtime configuration to be enabled.', 'duplicator-pro');
}
}
/**
* Get upload chunk size in bytes
*
* @return int bytes
*/
public function getUploadChunkSize(): int
{
$dGlobal = DynamicGlobalEntity::getInstance();
$chunkSizeKb = $dGlobal->getValInt('gdrive_upload_chunksize_in_kb', 256);
return $chunkSizeKb * KB_IN_BYTES;
}
/**
* Get download chunk size in bytes
*
* @return int bytes
*/
public function getDownloadChunkSize(): int
{
$dGlobal = DynamicGlobalEntity::getInstance();
$chunkSizeKb = $dGlobal->getValInt('gdrive_download_chunksize_in_kb', 10 * 1024);
return $chunkSizeKb * KB_IN_BYTES;
}
/**
* Get upload chunk timeout in seconds
*
* @return int timeout in microseconds, 0 unlimited
*/
public function getUploadChunkTimeout(): int
{
// @todo: fixed to 10 seconds for historical reasons, make it configurable.
return 10 * 1000000;
}
/**
* Check if storage is valid
*
* @param ?string $errorMsg Reference to store error message
* @param bool $force Force the storage to be revalidated
*
* @return bool Return true if storage is valid and ready to use, false otherwise
*/
public function isValid(?string &$errorMsg = '', bool $force = false): bool
{
if (!$this->isAuthorized()) {
$errorMsg = __('Google Drive isn\'t authorized.', 'duplicator-pro');
return false;
}
return true;
}
/**
* Is autorized
*
* @return bool
*/
public function isAuthorized(): bool
{
return (bool) ($this->config['authorized'] ?? false);
}
/**
* Returns an HTML anchor tag of location
*
* @return string Returns an HTML anchor tag with the storage location as a hyperlink.
*/
public function getHtmlLocationLink(): string
{
if (! $this->isAuthorized() || empty($this->config['storage_folder_web_url'])) {
return '<span>' . esc_html($this->getStorageFolder()) . '</span>';
}
return sprintf("<a href=\"%s\" target=\"_blank\">%s</a>", esc_url($this->config['storage_folder_web_url']), esc_html($this->getStorageFolder()));
}
/**
* Authorized from HTTP request
*
* @param string $message Message
*
* @return bool True if authorized, false if failed
*/
public function authorizeFromRequest(&$message = ''): bool
{
$tokenPairString = '';
try {
if (($refreshToken = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 'auth_code')) === '') {
throw new Exception(__('Authorization code is empty', 'duplicator-pro'));
}
$this->name = SnapUtil::sanitizeTextInput(SnapUtil::INPUT_REQUEST, 'name', '');
$this->notes = SnapUtil::sanitizeDefaultInput(SnapUtil::INPUT_REQUEST, 'notes', '');
$this->config['max_packages'] = SnapUtil::sanitizeIntInput(SnapUtil::INPUT_REQUEST, 'max_packages', 10);
$this->config['storage_folder'] = self::getSanitizedInputFolder('storage_folder', 'remove');
$this->revokeAuthorization();
$token = (new TokenEntity(static::getSType(), ['refresh_token' => $refreshToken]));
if (!$token->refresh(true)) {
throw new Exception(__('Failed to fetch information from Google Drive. Make sure the token is valid.', 'duplicator-pro'));
}
if (empty($token->getScope())) {
throw new Exception(__("Couldn't connect. Google Drive scopes not found.", 'duplicator-pro'));
}
if (! $token->hasScopes(static::REQUIRED_SCOPES)) {
throw new Exception(
__(
"Authorization failed. You did not allow all required permissions. Try again and make sure that you checked all checkboxes.",
'duplicator-pro'
)
);
}
$this->config['refresh_token'] = $token->getRefreshToken();
$this->config['token_json'] = wp_json_encode([
'created' => $token->getCreated(),
'access_token' => $token->getAccessToken(),
'refresh_token' => $token->getRefreshToken(),
'expires_in' => $token->getExpiresIn(),
'scope' => $token->getScope(),
]);
$this->config['client_number'] = self::GDRIVE_CLIENT_LATEST;
$this->config['authorized'] = $token->isValid();
} catch (Exception $e) {
DupLog::traceException($e, "Problem authorizing Google Drive access token");
DupLog::traceObject('Token pair string from authorization:', $tokenPairString);
$message = $e->getMessage();
return false;
}
$this->save();
$message = __('Google Drive is connected successfully and Storage Provider Updated.', 'duplicator-pro');
return true;
}
/**
* Revokes authorization
*
* @param string $message Message
*
* @return bool True if authorized, false if failed
*/
public function revokeAuthorization(&$message = ''): bool
{
if (!$this->isAuthorized()) {
$message = __('Google Drive isn\'t authorized.', 'duplicator-pro');
return true;
}
try {
$client = $this->getAdapter()->getService()->getClient();
if (!empty($this->config['refresh_token'])) {
$client->revokeToken($this->config['refresh_token']);
}
$accessTokenObj = json_decode($this->config['token_json']);
if (is_object($accessTokenObj) && property_exists($accessTokenObj, 'access_token')) {
$gdrive_access_token = $accessTokenObj->access_token;
} else {
$gdrive_access_token = false;
}
if (!empty($gdrive_access_token)) {
$client->revokeToken($gdrive_access_token);
}
} catch (Exception $e) {
DupLog::trace("Problem revoking Google Drive access token msg: " . $e->getMessage());
$message = $e->getMessage();
return false;
} finally {
$this->config['token_json'] = '';
$this->config['refresh_token'] = '';
$this->config['client_number'] = -1;
$this->config['authorized'] = false;
}
$message = __('Google Drive is disconnected successfully.', 'duplicator-pro');
return true;
}
/**
* Get authorization URL
*
* @return string
*/
public function getAuthorizationUrl(): string
{
return (new TokenService(static::getSType()))->getRedirectUri();
}
/**
* Get storage adapter
*
* @return GDriveAdapter
*/
protected function getAdapter(): GDriveAdapter
{
$global = GlobalEntity::getInstance();
$token = $this->getTokenFromConfig();
if (! $this->adapter) {
$storageFolderId = '';
if (! empty($this->config['storage_folder_id'])) {
$storageFolderId = $this->config['storage_folder_id'];
}
$this->adapter = new GDriveAdapter(
$token,
$this->config['storage_folder'],
$storageFolderId,
!$global->ssl_disableverify,
($global->ssl_useservercerts ? '' : DUPLICATOR_CERT_PATH),
$global->ipv4_only
);
$this->adapter->initialize();
if ($token->isValid() && empty($this->config['storage_folder_id'])) {
$storageFolder = $this->adapter->getPathInfo('/');
$this->config['storage_folder_id'] = $storageFolder->id;
$this->config['storage_folder_web_url'] = $storageFolder->webUrl;
$this->save();
}
}
if (! $token->isValid()) {
return $this->adapter;
}
// This check is only needed if we have a valid storage.
$storageFolder = $this->adapter->getPathInfo('/');
if ($storageFolder->name !== basename($this->getStorageFolder())) {
// root folder id & storage folder name is different.
$this->adapter = new GDriveAdapter(
$token,
$this->config['storage_folder'],
'',
!$global->ssl_disableverify,
($global->ssl_useservercerts ? '' : DUPLICATOR_CERT_PATH),
$global->ipv4_only
);
$this->adapter->initialize();
$storageFolder = $this->adapter->getPathInfo('/');
$this->config['storage_folder_id'] = $storageFolder->id;
$this->config['storage_folder_web_url'] = $storageFolder->webUrl;
$this->save();
}
return $this->adapter;
}
/**
* Returns the config fields template data
*
* @return array<string, mixed>
*/
protected function getConfigFieldsData(): array
{
$userInfo = false;
$quotaString = '';
$adapter = $this->getAdapter();
if ($this->isAuthorized() && $adapter->isValid()) {
try {
$serviceDrive = $adapter->getService();
$optParams = ['fields' => '*'];
$about = $serviceDrive->about->get($optParams);
$storageQuota = $about->getStorageQuota();
$quota_total = max($storageQuota->getLimit(), 1);
$quota_used = $storageQuota->getUsage();
$userInfo = $about->getUser();
if (is_numeric($quota_total) && is_numeric($quota_used)) {
$available_quota = $quota_total - $quota_used;
$used_perc = round($quota_used * 100 / $quota_total, 1);
$quotaString = sprintf(
__('%1$s%% used, %2$s available', 'duplicator-pro'),
$used_perc,
size_format($available_quota)
);
}
} catch (\Exception $e) {
DupLog::info("Problem getting Google Drive user info and quota: " . $e->getMessage());
$userInfo = $quotaString = null;
}
}
// Adapter is invalid, but we have a refresh token, so it has been revoked
if (! $adapter->isValid() && ! empty($this->config['refresh_token'])) {
$errorMessage = __('Google Drive has been disconnected. Please connect to Google Drive again.', 'duplicator-pro');
AdminNotices::displayGeneralAdminNotice($errorMessage, AdminNotices::GEN_ERROR_NOTICE);
}
return array_merge($this->getDefaultConfigFieldsData(), [
'userInfo' => $userInfo,
'quotaString' => $quotaString,
]);
}
/**
* Returns the default config fields template data
*
* @return array<string, mixed>
*/
protected function getDefaultConfigFieldsData(): array
{
return [
'storage' => $this,
'storageFolder' => $this->config['storage_folder'],
'maxPackages' => $this->config['max_packages'],
'userInfo' => null,
'quotaString' => null,
];
}
/**
* Returns the config fields template path
*
* @return string
*/
protected function getConfigFieldsTemplatePath(): string
{
return 'gdriveaddon/configs/google_drive';
}
/**
* Update data from http request, this method don't save data, just update object properties
*
* @param string $message Message
*
* @return bool True if success and all data is valid, false otherwise
*/
public function updateFromHttpRequest(&$message = ''): bool
{
if ((parent::updateFromHttpRequest($message) === false)) {
return false;
}
$previousStorageFolder = $this->config['storage_folder'];
$this->config['max_packages'] = SnapUtil::sanitizeIntInput(SnapUtil::INPUT_REQUEST, 'gdrive_max_files', 10);
$this->config['storage_folder'] = self::getSanitizedInputFolder('_gdrive_storage_folder', 'remove');
if ($previousStorageFolder !== $this->config['storage_folder']) {
$this->config['storage_folder_id'] = '';
$this->config['storage_folder_web_url'] = '';
}
$message = sprintf(
__('Google Drive Storage Updated.', 'duplicator-pro'),
$this->config['server'],
$this->getStorageFolder()
);
return true;
}
/**
* Get the token entity from config
*
* @return TokenEntity
*/
protected function getTokenFromConfig()
{
$token = new TokenEntity(static::getSType(), $this->config['token_json']);
if ($token->isValid() && $token->isAboutToExpire()) {
try {
if (! $token->refresh(true)) {
$token->updateProperties(['access_token' => '']); // clear access token
$this->config['authorized'] = false;
$this->save();
return $token;
}
} catch (Exception $e) {
DupLog::traceException($e, "Problem refreshing Google Drive access token");
}
$this->config['token_json'] = wp_json_encode([
'created' => $token->getCreated(),
'access_token' => $token->getAccessToken(),
'refresh_token' => $token->getRefreshToken(),
'expires_in' => $token->getExpiresIn(),
'scope' => $token->getScope(),
]);
$this->save();
}
return $token;
}
/**
* @return void
*/
public static function registerType(): void
{
parent::registerType();
add_action('duplicator_update_global_storage_settings', function (): void {
$dGlobal = DynamicGlobalEntity::getInstance();
foreach (static::getDefaultSettings() as $key => $default) {
$value = SnapUtil::sanitizeIntInput(SnapUtil::INPUT_REQUEST, $key, $default);
$dGlobal->setValInt($key, $value);
}
});
}
/**
* Get default settings
*
* @return array<string, scalar>
*/
protected static function getDefaultSettings(): array
{
return [
'gdrive_upload_chunksize_in_kb' => 1024,
'gdrive_download_chunksize_in_kb' => 10 * 1024,
];
}
/**
* @return void
*/
public static function renderGlobalOptions(): void
{
$dGlobal = DynamicGlobalEntity::getInstance();
TplMng::getInstance()->render(
'gdriveaddon/configs/global_options',
[
'uploadChunkSize' => $dGlobal->getValInt('gdrive_upload_chunksize_in_kb', 1024),
'downloadChunkSize' => $dGlobal->getValInt('gdrive_download_chunksize_in_kb', 10 * 1024),
]
);
}
}

View File

@@ -0,0 +1,33 @@
<?php
/**
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
namespace Duplicator\Addons\GDriveAddon\Models;
use Duplicator\Models\Storages\StoragePathInfo;
use VendorDuplicator\Google\Service\Drive\DriveFile;
class GDriveStoragePathInfo extends StoragePathInfo
{
/** @var string */
public $id = '';
/** @var string */
public $name = '';
/** @var string */
public $mimeType = '';
/** @var string */
public $webUrl = '';
/** @var string */
public $md5Checksum = '';
/** @var DriveFile */
public $file;
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Duplicator\Addons\GDriveAddon\Utils;
use Duplicator\Addons\GDriveAddon\GDriveAddon;
use Duplicator\Utils\AbstractAutoloader;
class Autoloader extends AbstractAutoloader
{
const VENDOR_PATH = GDriveAddon::ADDON_PATH . '/vendor-prefixed/';
/**
* Register autoloader function
*
* @return void
*/
public static function register(): void
{
spl_autoload_register([self::class, 'load']);
}
/**
* Load class
*
* @param string $className class name
*
* @return void
*/
public static function load($className): void
{
if (strpos($className, self::ROOT_VENDOR) === 0) {
foreach (self::getNamespacesVendorMapping() as $namespace => $mappedPath) {
if (strpos($className, (string) $namespace) !== 0) {
continue;
}
$filepath = self::getFilenameFromClass($className, $namespace, $mappedPath);
if (file_exists($filepath)) {
include $filepath;
return;
}
}
}
}
/**
* Return namespace mapping
*
* @return string[]
*/
protected static function getNamespacesVendorMapping(): array
{
$googleNS = 'Google\\'; // This to avoid StringClassNameToClassConstantRector replace rules
return [
self::ROOT_VENDOR . 'Firebase\\JWT' => self::VENDOR_PATH . 'firebase/php-jwt/src/',
self::ROOT_VENDOR . $googleNS . 'Service' => self::VENDOR_PATH . 'google/apiclient-services/src',
self::ROOT_VENDOR . $googleNS . 'Auth' => self::VENDOR_PATH . 'google/auth/src',
self::ROOT_VENDOR . 'Google' => self::VENDOR_PATH . 'google/apiclient/src',
self::ROOT_VENDOR . 'Monolog' => self::VENDOR_PATH . 'monolog/monolog/src/Monolog',
];
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Duplicator\Addons\GDriveAddon\Utils;
use VendorDuplicator\Google\Client;
use VendorDuplicator\GuzzleHttp\Client as GuzzleClient;
class GoogleClient extends Client
{
/** @var array<string,mixed> */
protected $customHttpOptions = [];
/**
* Set http client options
*
* @param array<string,mixed> $options options
*
* @return void
*/
public function setHttpClientOptions(array $options): void
{
$this->customHttpOptions = $options;
}
/**
* Create a new http client.
*
* @return GuzzleClient
*/
protected function createDefaultHttpClient()
{
$options = [
'base_uri' => $this->getConfig('base_path'),
'http_errors' => false,
];
$options = array_merge($options, $this->customHttpOptions);
return new GuzzleClient($options);
}
}

View File

@@ -0,0 +1,76 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Addons\GDriveAddon\Models\GDriveStorage;
use Duplicator\Libs\Snap\SnapServer;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
*/
?>
<div class="dup-accordion-wrapper display-separators close">
<div class="accordion-header">
<h3 class="title"><?php echo esc_html(GDriveStorage::getStypeName()); ?></h3>
</div>
<div class="accordion-content">
<label class="lbl-larger">
<?php esc_html_e("Upload Chunk Size", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-1">
<input
class="text-right inline-display width-small margin-bottom-0"
name="gdrive_upload_chunksize_in_kb"
id="gdrive_upload_chunksize_in_kb"
type="number"
min="256"
step="256"
data-parsley-required
data-parsley-type="number"
data-parsley-errors-container="#gdrive_upload_chunksize_in_kb_error_container"
value="<?php echo (int) $tplData['uploadChunkSize']; ?>">&nbsp;<b>KB</b>
<div id="gdrive_upload_chunksize_in_kb_error_container" class="duplicator-error-container"></div>
<p class="description">
<?php esc_html_e(
'How much should be uploaded to Google Drive per attempt. Higher=faster but less reliable. It should be multiple of 256.',
'duplicator-pro'
); ?>
</p>
</div>
<label class="lbl-larger">
<?php esc_html_e("Download Chunk Size", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-1">
<input
class="text-right inline-display width-small margin-bottom-0"
name="gdrive_download_chunksize_in_kb"
id="gdrive_download_chunksize_in_kb"
type="number"
min="256"
step="256"
data-parsley-required
data-parsley-type="number"
data-parsley-errors-container="#gdrive_download_chunksize_in_kb_error_container"
value="<?php echo (int) $tplData['downloadChunkSize']; ?>">&nbsp;<b>KB</b>
<div id="gdrive_download_chunksize_in_kb_error_container" class="duplicator-error-container"></div>
<p class="description">
<?php esc_html_e(
'How much should be downloaded from Google Drive per attempt.',
'duplicator-pro'
); ?>
</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,271 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Addons\GDriveAddon\Models\GDriveStorage;
use Duplicator\Views\UI\UiDialog;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var GDriveStorage $storage
*/
$storage = $tplData["storage"];
/** @var string */
$storageFolder = $tplData["storageFolder"];
/** @var int */
$maxPackages = $tplData["maxPackages"];
/** @var \VendorDuplicator\Google\Service\Drive\User $userInfo */
$userInfo = $tplData["userInfo"];
/** @var string */
$quotaString = $tplData["quotaString"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<tr>
<th scope="row"><label for=""><?php esc_html_e("Authorization", 'duplicator-pro'); ?></label></th>
<td>
<?php if (!$storage->isAuthorized()) : ?>
<div class='gdrive-authorization-state' id="gdrive-state-unauthorized">
<!-- CONNECT -->
<div id="dupli-gdrive-connect-btn-area">
<button
id="dupli-gdrive-connect-btn"
type="button"
class="button secondary hollow"
onclick="DupliJs.Storage.GDrive.GoogleGetAuthUrl();">
<i class="fa fa-plug"></i> <?php esc_html_e('Connect to Google Drive', 'duplicator-pro'); ?>
<img
src="<?php echo esc_url(DUPLICATOR_IMG_URL . '/google-drive.svg'); ?>"
style='vertical-align: middle; margin:-2px 0 0 3px; height:18px; width:18px' />
</button>
</div>
<div class="authorization-state" id="dupli-gdrive-connect-progress">
<div style="padding:10px">
<i class="fas fa-circle-notch fa-spin"></i> <?php esc_html_e('Getting Google Drive Request Token...', 'duplicator-pro'); ?>
</div>
</div>
<!-- STEPS -->
<div id="dupli-gdrive-steps">
<div class="storage-auth-step">
<p>
<b><?php esc_html_e('Step 1:', 'duplicator-pro'); ?></b>&nbsp;
<?php
esc_html_e(
"Duplicator needs to authorize Google Drive. Make sure to allow all required permissions.",
'duplicator-pro'
); ?>
</p>
<div class="auth-code-popup-note">
<?php esc_html_e(
'Note: Clicking the button below will open a new tab/window. Please be sure your browser does not block popups.',
'duplicator-pro'
); ?>
<?php esc_html_e(
'If a new tab/window does not open check your browsers address bar to allow popups from this URL.',
'duplicator-pro'
); ?>
</div>
<button
id="gdrive-auth-window-button"
class="button secondary hollow margin-bottom-0"
onclick="DupliJs.Storage.GDrive.OpenAuthPage(); return false;">
<i class="fa fa-user"></i> <?php esc_html_e("Authorize Google Drive", 'duplicator-pro'); ?>
</button>
</div>
<div class="storage-auth-step">
<p>
<b><?php esc_html_e('Step 2:', 'duplicator-pro'); ?></b>
<?php esc_html_e("Paste code from Google authorization page.", 'duplicator-pro'); ?>
</p>
<input style="width:400px" id="gdrive-auth-code" name="gdrive-auth-code" type="text" />
</div>
<div class="storage-auth-step">
<p>
<b><?php esc_html_e('Step 3:', 'duplicator-pro'); ?></b>
<?php esc_html_e('Finalize Google Drive setup by clicking the "Finalize Setup" button.', 'duplicator-pro') ?>
</p>
<button
id="gdrive-finalize-setup"
type="button"
class="button secondary margin-bottom-0">
<i class="fa fa-check-square"></i> <?php esc_html_e('Finalize Setup', 'duplicator-pro'); ?>
</button>
</div>
</div>
</div>
<?php else : ?>
<div class='gdrive-authorization-state' id="gdrive-state-authorized" style="margin-top:-10px">
<?php if ($userInfo != null) : ?>
<h3>
<?php esc_html_e('Google Drive Account', 'duplicator-pro'); ?><br />
<i class="dupli-edit-info">
<?php esc_html_e('Duplicator has been authorized to access this user\'s Google Drive account', 'duplicator-pro'); ?>
</i>
</h3>
<div id="gdrive-account-info">
<label><?php esc_html_e('Name', 'duplicator-pro'); ?>:</label>
<?php echo esc_html($userInfo->getDisplayName()); ?><br />
<label><?php esc_html_e('Email', 'duplicator-pro'); ?>:</label> <?php echo esc_html($userInfo->getEmailAddress()); ?>
<?php if (strlen($quotaString) > 0) { ?>
<br>
<label><?php esc_html_e('Quota', 'duplicator-pro'); ?>:</label> <?php echo esc_html($quotaString); ?>
<?php } ?>
</div><br />
<?php else : ?>
<div><?php esc_html_e('Error retrieving user information.', 'duplicator-pro'); ?></div>
<?php endif ?>
<button
id="dup-gdrive-cancel-authorization"
type="button"
class="button secondary hollow">
<?php esc_html_e('Cancel Authorization', 'duplicator-pro'); ?>
</button><br />
<i class="dupli-edit-info">
<?php
esc_html_e(
'Disassociates storage provider with the Google Drive account. Will require re-authorization.',
'duplicator-pro'
); ?>
</i>
</div>
<?php endif ?>
</td>
</tr>
<tr>
<th scope="row">
<label for="_gdrive_storage_folder">
<?php esc_html_e("Storage Folder", 'duplicator-pro'); ?>
</label>
</th>
<td>
<div class="horizontal-input-row">
<label for="_gdrive_storage_folder">
<b>//Google Drive/</b>
</label>
<input
id="_gdrive_storage_folder"
name="_gdrive_storage_folder"
type="text"
value="<?php echo esc_attr($storageFolder); ?>"
class="dupli-storeage-folder-path">
</div>
<p>
<i>
<?php
esc_html_e(
"Folder where backups will be stored. This should be unique for each web-site using Duplicator.",
'duplicator-pro'
); ?>
</i>
<?php
$tipContent = __(
'If the directory path above is already in Google Drive before connecting then a duplicate folder name will be made in the same path.',
'duplicator-pro'
) . ' google_drive.php' . __('This is because the plugin only has rights to folders it creates.', 'duplicator-pro');
?>
<i
class="fa-solid fa-question-circle fa-sm dark-gray-color"
data-tooltip-title="<?php esc_attr_e("Storage Folder Notice", 'duplicator-pro'); ?>"
data-tooltip="<?php esc_attr($tipContent); ?>">
</i>
</p>
</td>
</tr>
<tr>
<th scope="row"><label for=""><?php esc_html_e("Max Backups", 'duplicator-pro'); ?></label></th>
<td>
<div class="horizontal-input-row">
<input
id="gdrive_max_files"
name="gdrive_max_files"
type="number"
value="<?php echo (int) $maxPackages; ?>"
min="0"
maxlength="4"
data-parsley-errors-container="#gdrive_max_files_error_container"
data-parsley-required="true"
data-parsley-type="number"
data-parsley-min="0">&nbsp;
<label for="gdrive_max_files">
<?php esc_html_e("Number of Backups to keep in folder.", 'duplicator-pro'); ?> <br />
</label>
</div>
<?php $tplMng->render('admin_pages/storages/parts/max_backups_description'); ?>
<div id="gdrive_max_files_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<?php
$tplMng->render('admin_pages/storages/parts/provider_foot');
// Alerts for Google Drive
$alertConnStatus = new UiDialog();
$alertConnStatus->title = __('Google Drive Authorization Error', 'duplicator-pro');
$alertConnStatus->message = ''; // javascript inserted message
$alertConnStatus->initAlert();
?>
<script>
jQuery(document).ready(function($) {
DupliJs.Storage.GDrive = DupliJs.Storage.GDrive || {};
$('#dup-gdrive-cancel-authorization').click(function(event) {
event.stopPropagation();
DupliJs.Storage.RevokeAuth(<?php echo (int) $storage->getId(); ?>);
});
DupliJs.Storage.GDrive.GoogleGetAuthUrl = function() {
$('#dupli-gdrive-connect-btn-area').hide();
$('#dupli-gdrive-steps').show();
DupliJs.Storage.GDrive.AuthUrl = <?php echo json_encode($storage->getAuthorizationUrl()); ?>;
}
DupliJs.Storage.GDrive.OpenAuthPage = function() {
window.open(DupliJs.Storage.GDrive.AuthUrl, '_blank');
}
$('#gdrive-finalize-setup').click(function(event) {
event.stopPropagation();
if ($('#gdrive-auth-code').val().length > 5) {
DupliJs.Storage.PrepareForSubmit();
//$("#dup-storage-form").submit();
DupliJs.Storage.Authorize(
<?php echo (int) $storage->getId(); ?>,
<?php echo (int) $storage->getSType(); ?>, {
'name': $('#name').val(),
'notes': $('#notes').val(),
'storage_folder': $('#_gdrive_storage_folder').val(),
'max_packages': $('#gdrive_max_files').val(),
'auth_code': $('#gdrive-auth-code').val()
}
);
} else {
<?php $alertConnStatus->showAlert(); ?>
let alertMsg = "<i class='fas fa-exclamation-triangle'></i> " +
"<?php esc_html_e('Please enter your Google Drive authorization code!', 'duplicator-pro'); ?>";
<?php $alertConnStatus->updateMessage("alertMsg"); ?>
}
return false;
});
});
</script>