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,173 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Libs\Snap\SnapWP;
use Duplicator\Models\Storages\Local\LocalStorage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var LocalStorage $storage
*/
$storage = $tplData["storage"];
/** @var int */
$maxPackages = $tplData["maxPackages"];
/** @var int */
$isFilderProtection = $tplData["isFilderProtection"];
/** @var string */
$storageFolder = $tplData["storageFolder"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<tr valign="top">
<th scope="row">
<?php $home_path = SnapWP::getHomePath(true); ?>
<label onclick="jQuery('#_local_storage_folder').val('<?php echo esc_js($home_path); ?>')">
<?php esc_html_e("Storage Folder", 'duplicator-pro'); ?>
</label>
</th>
<td>
<div class="horizontal-input-row">
<input
data-parsley-errors-container="#_local_storage_folder_error_container"
data-parsley-required="true"
type="text"
id="_local_storage_folder"
class="dup-empty-field-on-submit"
name="_local_storage_folder"
data-parsley-pattern=".*"
data-parsley-not-core-paths="true"
value="<?php echo esc_attr($storageFolder); ?>">
<i class="fa-solid fa-question-circle fa-sm dark-gray-color margin-left-1"
data-tooltip-title="<?php esc_attr_e('Server storage folder', 'duplicator-pro'); ?>"
data-tooltip="<?php $tplMng->renderEscAttr('admin_pages/storages/configs/local_storage_folder_tooltip'); ?>">
</i>
</div>
<div id="_local_storage_folder_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<tr>
<th scope="row"><label for="local_filter_protection"><?php esc_html_e("Filter Protection", 'duplicator-pro'); ?></label></th>
<td>
<div class="horizontal-input-row">
<input
id="_local_filter_protection"
name="_local_filter_protection"
type="checkbox" <?php checked($isFilderProtection); ?>
onchange="DupliJs.Storage.LocalFilterToggle()">
<label for="_local_filter_protection">
<?php esc_html_e("Filter the Storage Folder (recommended)", 'duplicator-pro'); ?>
</label>
</div>
<div style="padding-top:6px">
<i>
<?php
esc_html_e(
"When checked this will exclude the 'Storage Folder' and all of its content and sub-folders from Backup builds.",
'duplicator-pro'
); ?>
</i>
<div id="_local_filter_protection_message" style="display:none; color:maroon">
<i>
<?php
esc_html_e(
"Unchecking filter protection is not recommended. This setting helps to prevents Backups from getting bundled in other Backups.",
'duplicator-pro'
); ?>
</i>
</div>
</div>
</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="local_max_files"
name="local_max_files"
type="number"
value="<?php echo (int) $maxPackages; ?>"
min="0"
maxlength="4"
data-parsley-errors-container="#local_max_files_error_container"
data-parsley-required="true"
data-parsley-type="number"
data-parsley-min="0">
<label for="local_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="local_max_files_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<?php $tplMng->render('admin_pages/storages/parts/provider_foot'); ?>
<script>
jQuery(document).ready(function($) {
let validatorMsg = <?php
echo json_encode(
__(
'Storage Folder should not be root directory path, content directory path and upload directory path',
'duplicator-pro'
)
); ?>;
window.Parsley.addValidator('notCorePaths', {
requirementType: 'string',
validateString: function(value) {
<?php
$home_path = SnapWP::getHomePath(true);
$wp_upload_dir = wp_upload_dir();
$wp_upload_dir_basedir = str_replace('\\', '/', $wp_upload_dir['basedir']);
?>
var corePaths = [
'<?php echo esc_js($home_path); ?>',
'<?php echo esc_js(untrailingslashit($home_path)); ?>',
'<?php echo esc_js($home_path . 'wp-content'); ?>',
'<?php echo esc_js($home_path . 'wp-content/'); ?>',
'<?php echo esc_js($home_path . 'wp-admin'); ?>',
'<?php echo esc_js($home_path . 'wp-admin/'); ?>',
'<?php echo esc_js($home_path . 'wp-includes'); ?>',
'<?php echo esc_js($home_path . 'wp-includes/'); ?>',
'<?php echo esc_js($wp_upload_dir_basedir); ?>',
'<?php echo esc_js(trailingslashit($wp_upload_dir_basedir)); ?>'
];
// console.log(value);
for (var i = 0; i < corePaths.length; i++) {
if (value === corePaths[i]) {
return false;
}
}
return true;
},
messages: {
en: validatorMsg
}
});
DupliJs.Storage.LocalFilterToggle = function() {
$("#_local_filter_protection").is(":checked") ?
$("#_local_filter_protection_message").hide(400) :
$("#_local_filter_protection_message").show(400);
};
//Init
DupliJs.Storage.LocalFilterToggle();
});
</script>

View File

@@ -0,0 +1,57 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\Local\LocalStorage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var LocalStorage $storage
*/
$storage = $tplData["storage"];
/** @var int */
$maxPackages = $tplData["maxPackages"];
/** @var string */
$storageFolder = $tplData["storageFolder"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<tr valign="top">
<th scope="row"><label><?php esc_html_e("Location", 'duplicator-pro'); ?></label></th>
<td><?php echo esc_html($storageFolder); ?></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
data-parsley-errors-container="#max_default_store_files_error_container"
id="max_default_store_files"
name="max_default_store_files"
type="text"
data-parsley-type="number"
data-parsley-min="0"
data-parsley-required="true"
value="<?php echo intval($maxPackages); ?>"
maxlength="4"
>
<label for="max_default_store_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="max_default_store_files_error_container" class="duplicator-error-container"></div>
</td>
</tr>
<?php $tplMng->render('admin_pages/storages/parts/provider_foot'); ?>

View File

@@ -0,0 +1,47 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Libs\Snap\SnapWP;
use Duplicator\Models\Storages\Local\LocalStorage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var LocalStorage $storage
*/
$storage = $tplData["storage"];
/** @var int */
$maxPackages = $tplData["maxPackages"];
/** @var int */
$isFilderProtection = $tplData["isFilderProtection"];
/** @var string */
$storageFolder = $tplData["storageFolder"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<?php esc_html_e("Where to store on the server hosting this site.", 'duplicator-pro'); ?><br>
<?php
printf(
esc_html_x(
'The folder can be either a child of the home directory (%1$s) or be outside it as well.',
'%1$s represents the home directory path',
'duplicator-pro'
),
'<b>' . esc_html(SnapWP::getHomePath(true)) . '</b>'
); ?><br>
<?php esc_html_e("On Linux servers start with '/' (e.g. /mypath). On Windows use drive letters (e.g. E:/mypath).", 'duplicator-pro'); ?><br>
<?php esc_html_e("If you are unsure of the path, contact your hosting provider.", 'duplicator-pro'); ?><br>
<br>
<b><?php esc_html_e('Note: This will not store to your local computer unless that is where this web-site is hosted.', 'duplicator-pro'); ?></b><br>

View File

@@ -0,0 +1,36 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\UnknownStorage;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var UnknownStorage $storage
*/
$storage = $tplData["storage"];
$tplMng->render('admin_pages/storages/parts/provider_head');
?>
<tr valign="top">
<th scope="row">
<label>
<?php esc_html_e("Unknown Storage Type", 'duplicator-pro'); ?>
</label>
</th>
<td>
</td>
</tr>
<?php $tplMng->render('admin_pages/storages/parts/provider_foot');

View File

@@ -0,0 +1,35 @@
<?php
/**
* Storage authorization success message template
*/
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var string $storagePageUrl Storage page URL
* @var string $storageName Storage name
* @var bool $isSettingsPage Whether authorization was from Settings page
*/
$storagePageUrl = $tplMng->getDataValueString('storagePageUrl');
$storageName = $tplMng->getDataValueString('storageName');
$isSettingsPage = $tplMng->getDataValueBool('isSettingsPage');
if ($isSettingsPage) {
printf(
esc_html__('Successfully connected to %1$s! You can manage/edit it from the %2$sStorage page%3$s.', 'duplicator-pro'),
'<strong>' . esc_html($storageName) . '</strong>',
'<a href="' . esc_url($storagePageUrl) . '">',
'</a>'
);
} else {
printf(
esc_html__('Successfully connected to %s!', 'duplicator-pro'),
'<strong>' . esc_html($storageName) . '</strong>'
);
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Core\Controllers\ControllersManager;
use Duplicator\Models\Storages\AbstractStorageEntity;
use Duplicator\Models\Storages\Local\DefaultLocalStorage;
use Duplicator\Models\Storages\Local\LocalStorage;
use Duplicator\Models\Storages\StoragesUtil;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
/** @var bool */
$blur = $tplData['blur'];
/** @var int */
$storage_id = $tplData["storage_id"];
$storage_tab_url = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG
);
$baseCopyUrl = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG,
null,
null,
[
ControllersManager::QUERY_STRING_INNER_PAGE => 'edit',
'action' => $tplData['actions']['copy-storage']->getKey(),
'_wpnonce' => $tplData['actions']['copy-storage']->getNonce(),
'storage_id' => $storage_id,
]
);
if ($storage->getId() > 0) {
$storages = AbstractStorageEntity::getAllBySType($storage->getSType());
} else {
$storages = AbstractStorageEntity::getAll(
0,
0,
[
StoragesUtil::class,
'sortByPriority',
],
fn(AbstractStorageEntity $s): bool => $s->getSType() !== LocalStorage::getSType() // Exclude local storage from the "Copy From" option list
);
}
if ($storages === false) {
$storages = [];
}
$storages = array_filter($storages, function (AbstractStorageEntity $s) use ($storage): bool {
if ($s->getId() == $storage->getId()) {
return false;
}
if ($s->getSType() == DefaultLocalStorage::getSType()) {
return false;
}
return true;
});
$storage_count = count($storages);
?>
<div class="dup-toolbar <?php echo ($blur ? 'dup-mock-blur' : ''); ?>">
<label for="dup-copy-source-id-select" class="screen-reader-text">Copy storage action</label>
<select
id="dup-copy-source-id-select"
name="dupli-source-storage-id"
class="small"
<?php disabled($storage_count < 1 || $storage->isLocal(), true); ?>>
<option value="-1" selected="selected" disabled="true">
<?php esc_html_e('Copy From', 'duplicator-pro'); ?>
</option>
<?php foreach ($storages as $copy_storage) { ?>
<option value="<?php echo (int) $copy_storage->getId(); ?>" data-stype="<?php echo (int) $copy_storage->getSType(); ?>">
<?php echo esc_html($copy_storage->getName()); ?> [<?php echo esc_html($copy_storage->getStypeName()); ?>]
</option>
<?php } ?>
</select>
<input
type="button"
id="dup-copy-storage-btn"
class="button hollow secondary small action"
value="<?php esc_attr_e("Apply", 'duplicator-pro') ?>"
onclick="DupliJs.Storage.Copy()"
<?php disabled($storage_count < 1 || $storage->isLocal(), true); ?>>
<span class="separator"></span>
<a
href="<?php echo esc_url($storage_tab_url); ?>"
class="button hollow secondary small "
title="<?php esc_attr_e('Back to storages list.', 'duplicator-pro'); ?>">
<i class="fas fa-server fa-sm"></i> <?php esc_html_e('Storages', 'duplicator-pro'); ?>
</a>
</div>
<hr class="dup-toolbar-divider" />
<script>
jQuery(document).ready(function($) {
// COMMON STORAGE RELATED METHODS
DupliJs.Storage.Copy = function() {
document.location.href = <?php echo json_encode($baseCopyUrl); ?> +
'&dupli-source-storage-id=' + $("#dup-copy-source-id-select option:selected").val();
};
});
</script>

View File

@@ -0,0 +1,32 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Controllers\SettingsPageController;
defined("ABSPATH") or die("");
?>
<p class="description">
<?php esc_html_e("When this limit is exceeded, the oldest Backup will be deleted. Set to 0 for no limit.", 'duplicator-pro'); ?>
<i
class="fa-solid fa-question-circle fa-sm dark-gray-color"
data-tooltip="<?php echo esc_attr(
sprintf(
_x(
'To configure how the associated backup record in the "Backups" screen is handled checkout the
%1$s"Delete Backup Records"%2$s setting.',
'1: <a> tag, 2: </a> tag',
'duplicator-pro'
),
'<a href="' . esc_url(SettingsPageController::getInstance()->getMenuLink(SettingsPageController::L2_SLUG_STORAGE)) . '">',
'</a>'
)
); ?>"
>
</i>
</p>

View File

@@ -0,0 +1,25 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\AbstractStorageEntity;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
?>
</table>

View File

@@ -0,0 +1,24 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\AbstractStorageEntity;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
?>
<table id="provider-<?php echo (int) $storage->getSType() ?>" class="provider form-table dup-remove-on-submit-if-hidden">

View File

@@ -0,0 +1,91 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Controllers\StoragePageController;
use Duplicator\Models\Storages\AbstractStorageEntity;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
/** @var bool */
$failed = $tplData["failed"];
/** @var bool */
$cancelled = $tplData["cancelled"];
/** @var bool */
$packageExists = $tplData["packageExists"];
$containerClasses = ['dup-dlg-store-endpoint'];
if ($failed) {
$containerClasses[] = 'dup-dlg-store-endpoint-failed';
}
if ($cancelled) {
$containerClasses[] = 'dup-dlg-store-endpoint-cancelled';
}
if (!$packageExists) {
$containerClasses[] = 'dup-dlg-store-package-not-found';
}
?>
<div class="<?php echo esc_attr(implode(' ', $containerClasses)); ?>" >
<h4 class="dup-dlg-store-names">
<?php
echo wp_kses(
$storage->getStypeIcon(),
[
'i' => [
'class' => [],
],
'img' => [
'src' => [],
'class' => [],
'alt' => [],
],
]
);
?>&nbsp;
<?php echo esc_html($storage->getStypeName()) ?>:&nbsp;
<span>
<?php echo esc_html($storage->getName()); ?>
<i>
<?php if ($failed) { ?>
(<?php esc_html_e('failed', 'duplicator-pro'); ?>)
<?php } elseif ($cancelled) { ?>
(<?php esc_html_e('cancelled', 'duplicator-pro'); ?>)
<?php } elseif (!$packageExists) { ?>
(<?php esc_html_e('backup not found', 'duplicator-pro'); ?>)
<?php } ?>
</i>
</span>
</h4>
<div class="dup-dlg-store-links">
<?php
echo wp_kses(
$storage->getHtmlLocationLink(),
[
'a' => [
'href' => [],
'target' => [],
],
]
);
?>
</div>
<div class="dup-dlg-store-test">
<a href="<?php echo esc_url(StoragePageController::getEditUrl($storage)); ?>" target='_blank'>
[ <?php esc_html_e('Test Storage', 'duplicator-pro'); ?> ]
</a>
</div>
</div>

View File

@@ -0,0 +1,79 @@
<?php
/**
* Duplicator storage error template
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Ajax\ServicesTools;
use Duplicator\Core\Controllers\ControllersManager;
use Duplicator\Utils\Support\SupportToolkit;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var Exception $e
*/
$e = $tplData["exception"];
$settings_url = ControllersManager::getMenuLink(ControllersManager::SETTINGS_SUBMENU_SLUG);
$fullError = $e->getMessage() . "\n\n" . $e->getTraceAsString();
?>
<div class="dup-storage-error-wrapper">
<div class="error-txt">
<h3><?php esc_html_e('Oops, there was a problem...', 'duplicator-pro'); ?></h3>
<p>
<?php esc_html_e('An error has occurred while trying to read a storage item! ', 'duplicator-pro'); ?>
<?php esc_html_e(
'To resolve this issue edit the storage, re-enter its information and if appropriate re-authorize the plugin. ',
'duplicator-pro'
); ?>
</p>
<p>
<?php esc_html_e(
'This problem can be due to a security plugin changing keys in wp-config.php, causing the storage information to become unreadable.',
'duplicator-pro'
); ?>
<?php
printf(
esc_html__(
'If such a plugin is doing this then either disable the key changing functionality
in the security plugin or go to %1$sDuplicator Pro > Settings%2$s and disable settings encryption.',
'duplicator-pro'
),
'<a href="' . esc_url($settings_url) . '">',
'</a>'
);
?>
</p>
<p>
<?php esc_html_e('If the problem persists after doing these things then please contact the support team.', 'duplicator-pro'); ?>
<?php if (SupportToolkit::isAvailable()) {
printf(
esc_html__(
'Please make sure to attach the %1$sdiagnostic data%2$s and the error message below to your ticket.',
'duplicator-pro'
),
'<a href="' . esc_url(SupportToolkit::getSupportToolkitDownloadUrl()) . '">',
'</a>'
);
} ?>
</p>
</div>
<div class="error-trace-copy">
<textarea class="dup-error-message-textarea" disabled ><?php echo esc_textarea($fullError); ?></textarea>
<button
data-dup-copy-value="<?php echo esc_attr($fullError); ?>"
data-dup-copy-title="<?php echo esc_attr("Copy Error Message to clipboard"); ?>"
data-dup-copied-title="<?php echo esc_attr("Error Message copied to clipboard"); ?>"
class="button dup-btn-copy-error-message">
<?php esc_html_e('Copy error details', 'duplicator-pro'); ?>
</button>
</div>
</div>

View File

@@ -0,0 +1,295 @@
<?php
/**
* Duplicator messages sections
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\AbstractStorageEntity;
use Duplicator\Core\Addons\AddonsManager;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
$sTypeSelected = ($storage->isSelectable() ? $storage->getSType() : -1);
$types = AbstractStorageEntity::getResisteredTypesByPriority();
$isEditMode = ($storage->getId() < 0);
// Collect storage types for display
$storageTypes = [];
foreach ($types as $type) {
$class = AbstractStorageEntity::getSTypePHPClass($type);
if (!call_user_func([$class, 'isSelectable'])) {
continue;
}
$disabledReason = '';
$isDisabled = call_user_func_array([$class, 'isSelectDisabled'], [&$disabledReason]);
$storageTypes[] = [
'type' => $type,
'class' => $class,
'name' => call_user_func([$class, 'getStypeName']),
'icon' => call_user_func([$class, 'getStypeIcon']),
'disabled' => $isDisabled,
'reason' => $disabledReason,
'gridBreak' => call_user_func([$class, 'isGridBreakAfter']),
];
}
?>
<div class="dup-storage-type-selector" id="dup-storage-type-selector">
<span class="dup-storage-type-selector__current" id="dup-storage-current">
<?php
echo wp_kses(
$storage->getStypeIcon(),
[
'i' => [
'class' => [],
],
'img' => [
'src' => [],
'class' => [],
'alt' => [],
],
]
);
?>
<span><?php echo esc_html($storage->getStypeName()); ?></span>
</span>
<?php if ($isEditMode) : ?>
<button type="button" class="dup-storage-type-selector__toggle button primary hollow margin-bottom-0" id="dup-storage-toggle">
<?php esc_html_e('Select', 'duplicator-pro'); ?>
</button>
<div class="dup-storage-type-selector__grid" id="dup-storage-grid">
<div class="dup-storage-type-selector__grid-inner">
<?php foreach ($storageTypes as $storageType) : ?>
<?php
$cardClasses = 'dup-storage-card';
$cardClasses .= ($sTypeSelected === $storageType['type']) ? ' is-selected' : '';
$cardClasses .= $storageType['disabled'] ? ' is-disabled' : '';
$cardTitle = $storageType['disabled'] ? $storageType['reason'] : $storageType['name'];
?>
<label
class="<?php echo esc_attr($cardClasses); ?>"
title="<?php echo esc_attr($cardTitle); ?>"
data-storage-type="<?php echo (int) $storageType['type']; ?>"
data-storage-name="<?php echo esc_attr($storageType['name']); ?>"
data-storage-disabled="<?php echo $storageType['disabled'] ? '1' : '0'; ?>"
>
<input
type="radio"
name="storage_type_radio"
value="<?php echo (int) $storageType['type']; ?>"
<?php checked($sTypeSelected, $storageType['type']); ?>
<?php disabled($storageType['disabled']); ?>
>
<?php
echo wp_kses(
$storageType['icon'],
[
'i' => ['class' => []],
'img' => [
'src' => [],
'class' => [],
'alt' => [],
],
]
);
?>
<div class="label" >
<?php echo esc_attr($storageType['name']); ?>
</div>
<?php if ($storageType['disabled']) : ?>
<span class="dup-storage-card__disabled-overlay"></span>
<?php endif; ?>
</label>
<?php if ($storageType['gridBreak']) : ?>
<div class="dup-storage-grid-break"></div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
<select id="change-mode" name="storage_type" onchange="DupliJs.Storage.ChangeMode()" class="width-medium" style="display: none;">
<?php foreach ($storageTypes as $storageType) : ?>
<option
value="<?php echo (int) $storageType['type']; ?>"
<?php selected($sTypeSelected, $storageType['type']); ?>
<?php disabled($storageType['disabled']); ?>
>
<?php echo esc_html($storageType['name']); ?>
</option>
<?php endforeach; ?>
</select>
<?php else : ?>
<span id="dup-storage-mode-fixed" data-storage-type="<?php echo (int) $storage->getSType(); ?>" style="display: none;"></span>
<?php endif; ?>
</div>
<script>
jQuery(document).ready(function ($) {
DupliJs.Storage.InitTypeSelector = function($container) {
const $toggle = $container.find('.dup-storage-type-selector__toggle');
const $cards = $container.find('.dup-storage-card');
const $current = $container.find('.dup-storage-type-selector__current');
const $select = $('#change-mode');
$toggle.on('click', function() {
$container.toggleClass('is-open');
});
$cards.on('click', function() {
const $card = $(this);
const isDisabled = $card.data('storage-disabled') === 1;
// Prevent selection of disabled storage types
if (isDisabled) {
return false;
}
const storageType = $card.data('storage-type');
const storageName = $card.data('storage-name');
const $icon = $card.find('i, img').clone();
$card.find('input[type="radio"]').prop('checked', true);
$select.val(storageType).trigger('change');
$cards.removeClass('is-selected');
$card.addClass('is-selected');
$current.html($icon.add('<span>' + storageName + '</span>'));
$container.removeClass('is-open');
DupliJs.Storage.ChangeMode();
});
};
// Initialize the type selector if it exists
const $typeSelector = $('#dup-storage-type-selector');
if ($typeSelector.length > 0) {
DupliJs.Storage.InitTypeSelector($typeSelector);
}
DupliJs.Storage.BindParsley = function (node)
{
$('#dup-storage-form').parsley().destroy();
$('#dup-storage-form .provider input').attr('data-parsley-excluded', 'true');
node.find('input').removeAttr('data-parsley-excluded');
$('#dup-storage-form').parsley();
};
DupliJs.Storage.Autofill = function (mode) {
<?php if (AddonsManager::getInstance()->isAddonEnabled('AmazonS3Addon')) : ?>
switch (parseInt(mode)) {
case <?php echo (int) \Duplicator\Addons\AmazonS3Addon\Models\BackblazeStorage::getSType(); ?>:
case <?php echo (int) \Duplicator\Addons\AmazonS3Addon\Models\DreamStorage::getSType(); ?>:
autoFillRegion(mode, 1);
break;
case <?php echo (int) \Duplicator\Addons\AmazonS3Addon\Models\VultrStorage::getSType(); ?>:
case <?php echo (int) \Duplicator\Addons\AmazonS3Addon\Models\DigitalOceanStorage::getSType(); ?>:
autoFillRegion(mode, 0);
break;
case <?php echo (int) \Duplicator\Addons\AmazonS3Addon\Models\WasabiStorage::getSType(); ?>:
let wasabiRegion = $("#s3_region_" + mode);
let wasabiEndpoint = $("#s3_endpoint_" + mode);
wasabiRegion.change(function(e) {
if (wasabiEndpoint.val().length > 0) {
return;
}
let regionVal = $(this).val();
if (regionVal.length > 0) {
wasabiEndpoint.val("s3." + regionVal + ".wasabisys.com");
} else {
wasabiEndpoint.val("");
}
});
break;
}
function autoFillRegion(type, regionPos) {
let region = $("#s3_region_" + type);
let endpoint = $("#s3_endpoint_" + type);
endpoint.change(function(e) {
bindEndpointToRegion(region, endpoint, regionPos);
});
}
function bindEndpointToRegion(region, endpoint, pos) {
if (region.val().length > 0) {
return;
}
if (endpoint.val().length > 0) {
let regionStr = endpoint.val().replace(/.*:\/\//g,'').split(".")[pos];
region.val(regionStr);
} else {
region.val("");
}
}
<?php else : ?>
return;
<?php endif; ?>
}
// GENERAL STORAGE LOGIC
DupliJs.Storage.ChangeMode = function (animateOverride = 400) {
const mode = $('#dup-storage-mode-fixed').length > 0
? $('#dup-storage-mode-fixed').data('storage-type')
: $('#change-mode option:selected').val();
// Reset the copy source ID select
$('#dup-copy-source-id-select').val(-1);
// Disable copy controls for local storage
const isCopyDisabled = parseInt(mode) === 0;
$('#dup-copy-source-id-select, #dup-copy-storage-btn').prop('disabled', isCopyDisabled);
// Disable non-matching options
$('#dup-copy-source-id-select option').each(function () {
const option = $(this);
const optionType = option.data('stype');
option.prop('disabled', optionType !== parseInt(mode));
// Hide options that are disabled
if (option.prop('disabled')) {
option.hide();
} else {
option.show();
}
});
const providerConfigNode = $('#provider-' + mode);
$('.provider').hide();
providerConfigNode.show(animateOverride);
DupliJs.Storage.BindParsley(providerConfigNode);
DupliJs.Storage.Autofill(mode);
}
$('#dup-storage-form').parsley();
DupliJs.Storage.ChangeMode(0);
});
</script>

View File

@@ -0,0 +1,119 @@
<?php
/**
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Models\Storages\AbstractStorageEntity;
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 AbstractStorageEntity $storage
*/
$storage = $tplData["storage"];
$errorMessage = '';
$buttonDisabled = ($storage->getId() < 0 || $storage->isValid($errorMessage, true) == false);
?>
<table class="form-table">
<tr>
<th scope="row">
<label for=""><?php esc_html_e("Validation", 'duplicator-pro'); ?></label>
</th>
<td>
<button
id="button_file_test"
class="button secondary hollow small button_file_test margin-bottom-0"
type="button"
onclick="DupliJs.Storage.Test(); return false;"
<?php disabled($buttonDisabled); ?>>
<i class="fas fa-cloud-upload-alt fa-sm"></i> <?php esc_html_e('Test Storage', 'duplicator-pro'); ?>
</button>
<p>
<i><?php esc_html_e("Test creating and deleting a small file on storage.", 'duplicator-pro'); ?></i>
</p>
</td>
</tr>
</table>
<?php
$alertStorageStatus = new UiDialog();
$alertStorageStatus->title = __('Storage Status', 'duplicator-pro');
$alertStorageStatus->height = 185;
$alertStorageStatus->message = 'testings'; // javascript inserted message
$alertStorageStatus->initAlert();
$alertStorageStatusLong = new UiDialog();
$alertStorageStatusLong->title = __('Storage Status', 'duplicator-pro');
$alertStorageStatusLong->width = 800;
$alertStorageStatusLong->height = 520;
$alertStorageStatusLong->showTextArea = true;
$alertStorageStatusLong->textAreaRows = 15;
$alertStorageStatusLong->textAreaCols = 100;
$alertStorageStatusLong->message = ''; // javascript inserted message
$alertStorageStatusLong->initAlert();
?>
<script>
jQuery(document).ready(function($) {
DupliJs.Storage.Test = function() {
var $test_button = $('#button_file_test');
$test_button.html('<i class="fas fa-circle-notch fa-spin"></i> <?php esc_html_e('Attempting to test storage', 'duplicator-pro'); ?>');
DupliJs.Util.ajaxWrapper({
action: 'duplicator_storage_test',
storage_id: <?php echo (int) $storage->getId(); ?>,
nonce: '<?php echo esc_js(wp_create_nonce('duplicator_storage_test')); ?>'
},
function(result, data, funcData, textStatus, jqXHR) {
console.log('Func data', funcData);
if (funcData.success) {
if (funcData.status_msgs.length == 0) {
<?php $alertStorageStatus->showAlert(); ?>
let alertMsg = "<span style='color:green'><b><input type='checkbox' class='checkbox' checked disabled='disabled'>" +
funcData.message + "</b></span>";
<?php $alertStorageStatus->updateMessage("alertMsg"); ?>
} else {
<?php $alertStorageStatusLong->showAlert(); ?>
<?php $alertStorageStatusLong->updateTextareaMessage("funcData.status_msgs"); ?>
let alertMsg = "<span style='color:green'><b><input type='checkbox' class='checkbox' checked disabled='disabled'>" +
funcData.message + "</b></span>";
<?php $alertStorageStatusLong->updateMessage("alertMsg"); ?>
}
} else {
if (funcData.status_msgs.length == 0) {
<?php $alertStorageStatus->showAlert(); ?>
let alertMsg = "<i class='fas fa-exclamation-triangle'></i> " + funcData.message;
<?php $alertStorageStatus->updateMessage("alertMsg"); ?>
} else {
<?php $alertStorageStatusLong->showAlert(); ?>
<?php $alertStorageStatusLong->updateTextareaMessage("funcData.status_msgs"); ?>
let alertMsg = "<i class='fas fa-exclamation-triangle'></i> " + funcData.message;
<?php $alertStorageStatusLong->updateMessage("alertMsg"); ?>
}
}
$test_button.html('<i class="fas fa-cloud-upload-alt fa-sm"></i> <?php esc_html_e('Test Storage', 'duplicator-pro'); ?>');
return '';
},
function(result, data, funcData, textStatus, jqXHR) {
$test_button.html('<i class="fas fa-cloud-upload-alt fa-sm"></i> <?php esc_html_e('Test Storage', 'duplicator-pro'); ?>');
<?php $alertStorageStatus->showAlert(); ?>
let alertMsg = "<i class='fas fa-exclamation-triangle'></i> <?php esc_html_e('AJAX error while testing storage.', 'duplicator-pro'); ?> ";
<?php $alertStorageStatus->updateMessage("alertMsg"); ?>
console.log(data);
return '';
}
);
}
});
</script>

View File

@@ -0,0 +1,53 @@
<?php
/**
* Duplicator Backup row in table Backups list
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*/
use Duplicator\Controllers\StoragePageController;
use Duplicator\Core\CapMng;
defined("ABSPATH") or die("");
/**
* Variables
*
* @var \Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var \Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var bool $blur
*/
$blur = $tplData['blur'];
if (CapMng::can(CapMng::CAP_STORAGE, false) && !$blur) {
$edit_storage_url = $ctrlMng::getMenuLink(
$ctrlMng::STORAGE_SUBMENU_SLUG,
null,
null,
[
$ctrlMng::QUERY_STRING_INNER_PAGE => StoragePageController::INNER_PAGE_EDIT,
]
);
$tipContent = __(
'Create a new Storage.',
'duplicator-pro'
);
?>
<span
class="dup-new-package-wrapper"
data-tooltip="<?php echo esc_attr($tipContent); ?>"
>
<a
href="<?php echo esc_url($edit_storage_url); ?>"
id="dupli-create-new"
class="button primary tiny font-bold margin-bottom-0"
>
<?php esc_html_e('Add New', 'duplicator-pro'); ?>
</a>
</span>
<?php
}

View File

@@ -0,0 +1,132 @@
<?php
/**
* @package Duplicator
*/
defined("ABSPATH") or die("");
use Duplicator\Controllers\SettingsPageController;
use Duplicator\Core\Controllers\ControllersManager;
use Duplicator\Models\Storages\AbstractStorageEntity;
use Duplicator\Views\AdminNotices;
/**
* Variables
*
* @var Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var bool $blur
*/
$blur = $tplData['blur'];
/** @var int */
$storage_id = $tplData["storage_id"];
/** @var Duplicator\Models\Storages\AbstractStorageEntity */
$storage = $tplData["storage"];
/** @var ?string */
$error_message = $tplData["error_message"];
/** @var ?string */
$success_message = $tplData["success_message"];
$relativeEditUrl = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG,
SettingsPageController::L2_SLUG_STORAGE,
null,
[ControllersManager::QUERY_STRING_INNER_PAGE => 'edit']
);
$fullEditUrl = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG,
SettingsPageController::L2_SLUG_STORAGE,
null,
[ControllersManager::QUERY_STRING_INNER_PAGE => 'edit'],
false
);
?>
<form
id="dup-storage-form"
class="dup-monitored-form <?php echo ($blur ? 'dup-mock-blur' : ''); ?>"
action="<?php echo esc_url($relativeEditUrl); ?>"
method="post"
data-parsley-ui-enabled="true"
target="_self"
>
<?php $tplData['actions']['save']->getActionNonceFileds(); ?>
<input type="hidden" name="storage_id" id="storage_id" value="<?php echo (int) $storage->getId(); ?>">
<?php
$tplMng->render('admin_pages/storages/parts/edit_toolbar');
if (!is_null($error_message)) {
AdminNotices::displayGeneralAdminNotice($error_message, AdminNotices::GEN_ERROR_NOTICE, true);
} elseif (!is_null($success_message)) {
AdminNotices::displayGeneralAdminNotice($success_message, AdminNotices::GEN_SUCCESS_NOTICE, true);
}
?>
<div class="form-table dup-settings-wrapper">
<label class="lbl-larger">
<?php esc_html_e("Name", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-1">
<?php if ($storage->isDefault()) {
esc_html_e('Default', 'duplicator-pro');
$tCont = __('The "Default" storage type is a built in type that cannot be removed.', 'duplicator-pro') . ' ' .
__(' This storage type is used by default should no other storage types be available.', 'duplicator-pro') . ' ' .
__('This storage type is always stored to the local server.', 'duplicator-pro');
?>
<i
class="fa-solid fa-question-circle fa-sm dark-gray-color"
data-tooltip-title="<?php esc_attr_e("Default Storage Type", 'duplicator-pro'); ?>"
data-tooltip="<?php echo esc_attr($tCont); ?>"
>
</i>
<?php } else { ?>
<input
data-parsley-errors-container="#name_error_container"
type="text"
id="name"
name="name"
value="<?php echo esc_attr($storage->getName()); ?>" autocomplete="off"
>
<?php } ?>
<div id="name_error_container" class="duplicator-error-container"></div>
</div>
<label class="lbl-larger">
<?php esc_html_e("Notes", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-1">
<textarea id="notes" name="notes" style="width:100%; max-width: 500px"><?php echo esc_textarea($storage->getNotes()); ?></textarea>
</div>
<label class="lbl-larger">
<?php esc_html_e("Type", 'duplicator-pro'); ?>
</label>
<div class="margin-bottom-0">
<?php $tplMng->render('admin_pages/storages/parts/storage_type_select'); ?>
</div>
</div>
<hr size="1" />
<?php
if ($storage->getId() > 0) {
$storage->renderConfigFields();
} else {
$types = AbstractStorageEntity::getResisteredTypes();
foreach ($types as $type) {
AbstractStorageEntity::renderSTypeConfigFields($type);
}
}
$tplMng->render('admin_pages/storages/parts/test_button');
?>
<br style="clear:both" />
<button
id="button_save_provider"
class="button primary small"
type="submit"
>
<?php esc_html_e('Save Provider', 'duplicator-pro'); ?>
</button>
</form>
<?php
$tplMng->render('admin_pages/storages/storage_scripts');

View File

@@ -0,0 +1,358 @@
<?php
/**
* @package Duplicator
*/
defined("ABSPATH") or die("");
use Duplicator\Ajax\ServicesStorage;
use Duplicator\Controllers\SettingsPageController;
use Duplicator\Controllers\StoragePageController;
use Duplicator\Core\CapMng;
use Duplicator\Core\Controllers\ControllersManager;
use Duplicator\Core\Views\TplMng;
use Duplicator\Models\Storages\AbstractStorageEntity;
use Duplicator\Models\Storages\StoragesUtil;
use Duplicator\Views\UI\UiDialog;
/**
* Variables
*
* @var Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
*/
$blur = $tplMng->getDataValueBool('blur');
$storages = AbstractStorageEntity::getAll(0, 0, [StoragesUtil::class, 'sortDefaultFirst']);
$numStorages = ($storages === false) ? 0 : count($storages);
$edit_storage_url = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG,
null,
null,
[
ControllersManager::QUERY_STRING_INNER_PAGE => StoragePageController::INNER_PAGE_EDIT,
]
);
$storage_tab_url = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG,
SettingsPageController::L2_SLUG_STORAGE
);
$settingsStorageUrl = ControllersManager::getMenuLink(
ControllersManager::SETTINGS_SUBMENU_SLUG,
SettingsPageController::L2_SLUG_STORAGE
);
$baseCopyUrl = ControllersManager::getMenuLink(
ControllersManager::STORAGE_SUBMENU_SLUG,
SettingsPageController::L2_SLUG_STORAGE,
null,
[
ControllersManager::QUERY_STRING_INNER_PAGE => 'edit',
'action' => $tplData['actions']['copy-storage']->getKey(),
'_wpnonce' => $tplData['actions']['copy-storage']->getNonce(),
]
);
?>
<div class="dup-toolbar <?php echo ($blur ? 'dup-mock-blur' : ''); ?>">
<label for="bulk_action" class="screen-reader-text">Select bulk action</label>
<select id="bulk_action" class="small">
<option value="-1" selected>
<?php esc_html_e("Bulk Actions", 'duplicator-pro') ?>
</option>
<?php if (CapMng::can(CapMng::CAP_STORAGE, false)) { ?>
<option value="<?php echo (int) ServicesStorage::STORAGE_BULK_DELETE; ?>" title="Delete selected storage endpoint(s)">
<?php esc_html_e('Delete', 'duplicator-pro'); ?>
</option>
<?php } ?>
</select>
<input
type="button"
id="dup-pack-bulk-apply"
class="button hollow secondary small"
value="<?php esc_attr_e("Apply", 'duplicator-pro') ?>"
onclick="DupliJs.Storage.BulkAction()">
<span class="separator"></span>
<?php if (CapMng::can(CapMng::CAP_SETTINGS, false)) { ?>
<a href="<?php echo esc_url($settingsStorageUrl); ?>"
class="button hollow secondary small dupli-toolbar-settings"
title="<?php esc_attr_e("Storage Settings", 'duplicator-pro'); ?>">
<i class="fas fa-sliders-h fa-fw"></i>
</a>
<?php } ?>
</div>
<form
id="dup-storage-form"
action="<?php echo esc_url($storage_tab_url); ?>"
method="post"
class="<?php echo ($blur ? 'dup-mock-blur' : ''); ?>">
<input type="hidden" id="dup-selected-storage" name="storage_id" value="null" />
<!-- ====================
LIST ALL STORAGE -->
<table class="widefat storage-tbl dup-table-list valign-top dup-packtbl">
<thead>
<tr>
<th style='width:10px;'>
<input
type="checkbox"
id="dupli-chk-all"
title="Select all storage endpoints" onclick="DupliJs.Storage.SetAll(this)"
class="margin-bottom-0">
</th>
<th style='width:275px;'>Name</th>
<th><?php esc_html_e('Type', 'duplicator-pro'); ?></th>
</tr>
</thead>
<tbody>
<?php
if ($storages === false) {
$tplMng->render('admin_pages/storages/storage_list_row_error');
} else {
foreach ($storages as $index => $storage) {
if ($storage->isHidden()) {
continue;
}
$tplMng->render('admin_pages/storages/storage_list_row', [
'storage' => $storage,
'index' => $index,
]);
};
}
?>
</tbody>
<tfoot>
<tr>
<th colspan="8" style="text-align:right; font-size:12px">
<?php echo esc_html__('Total', 'duplicator-pro') . ': ' . (int) $numStorages; ?>
</th>
</tr>
</tfoot>
</table>
</form>
<?php
//Select Action Alert
$alert1 = new UiDialog();
$alert1->title = __('Bulk Action Required', 'duplicator-pro');
$alert1->message = __('Please select an action from the "Bulk Actions" drop down menu!', 'duplicator-pro');
$alert1->initAlert();
//Select Storage Alert
$alert2 = new UiDialog();
$alert2->title = __('Selection Required', 'duplicator-pro');
$alert2->message = __('Please select at least one storage to delete!', 'duplicator-pro');
$alert2->initAlert();
//Delete Dialog
$dlgDelete = new UiDialog();
$dlgDelete->height = 525;
$dlgDelete->title = __('Delete Storage(s)?', 'duplicator-pro');
$dlgDelete->progressText = __('Removing Storages, Please Wait...', 'duplicator-pro');
$dlgDelete->jsCallback = 'DupliJs.Storage.deleteAjax()';
$dlgDelete->initConfirm();
$storage_bulk_action_nonce = wp_create_nonce("duplicator_storage_bulk_actions");
?>
<script>
jQuery(document).ready(function($) {
//Shows detail view
DupliJs.Storage.Edit = function(id) {
document.location.href = <?php echo json_encode($edit_storage_url); ?> + '&storage_id=' + id;
};
//Copy and edit
DupliJs.Storage.CopyEdit = function(id) {
document.location.href = <?php echo json_encode($baseCopyUrl); ?> + '&dupli-source-storage-id=' + id;
};
//Shows detail view
DupliJs.Storage.View = function(id) {
$('#quick-view-' + id).toggle();
};
//Select all checked items
DupliJs.Storage.SelectedList = function() {
var arr = [];
$("input[name^='selected_id[]']").each(function() {
if ($(this).is(':checked')) {
arr.push($(this).val());
}
});
return arr;
};
//Sets all for deletion
DupliJs.Storage.SetAll = function(chkbox) {
$('.item-chk').each(function() {
this.checked = chkbox.checked;
});
};
// Bulk action
DupliJs.Storage.BulkAction = function() {
var list = DupliJs.Storage.SelectedList();
var action = $('#bulk_action').val();
if (list.length === 0) {
<?php $alert2->showAlert(); ?>
return;
}
switch (action) {
case '<?php echo (int) ServicesStorage::STORAGE_BULK_DELETE; ?>':
DupliJs.Storage.deleteConfirm(list);
break;
default:
<?php $alert1->showAlert(); ?>
break;
}
};
//Delete via the delete link
DupliJs.Storage.deleteSingle = function(id) {
$('#dup-selected-storage').val(id);
DupliJs.Storage.deleteConfirm([id]);
};
//Load the delete confirm dialog
DupliJs.Storage.deleteConfirm = function(idList) {
var $rowData;
var name, id, typeName, html;
var storeCount = idList.length;
var isSingle = (storeCount == 1) ? true : false;
var dlgID = "<?php echo esc_js($dlgDelete->getID()); ?>";
var $content = $(`#${dlgID}_message`);
html = (isSingle) ?
"<i><?php esc_html_e('Are you sure you want to delete this storage item?', 'duplicator-pro') ?></i>" :
`<i><?php esc_html_e('Are you sure you want to delete these ${storeCount} storage items?', 'duplicator-pro') ?></i>`;
// Build storage item html
html += '<div class="store-items">';
idList.forEach(v => {
html += $('#main-view-' + v).data('delete-view');
});
html += '</div>';
$content.html(html);
<?php $dlgDelete->showConfirm(); ?>
html = `<div class="schedule-area">
<b><?php esc_html_e('Linked Schedules', 'duplicator-pro') ?>:</b><br/>
<small><?php esc_html_e("Schedules linked to the storage items above", 'duplicator-pro'); ?>:</small>
<div class="schedule-progress" id="${dlgID}-schedule-progress">
<i class="fas fa-circle-notch fa-spin"></i>
<?php esc_html_e('Finding Schedule Links... Please wait', 'duplicator-pro') ?>
</div>
<small>
<?php
esc_html_e("To remove storage items and unlink schedules click OK. ", 'duplicator-pro');
printf(
esc_html_x(
'Schedules with asterisk%1$s will be deactivated if storage is removed.',
'%1$s is an asterisk symbol',
'duplicator-pro'
),
'<span class="maroon">*</span>'
);
?>
</small>
</div>`;
$content.append(html);
function loadSchedules(idList, dlgID) {
let result = DupliJs.Storage.getScheduleData(idList);
(result != null) ?
$(`#${dlgID}-schedule-progress`).html(result):
$(`#${dlgID}-schedule-progress`).html("<?php esc_html_e('- No linked schedules found -', 'duplicator-pro') ?>");
}
setTimeout(loadSchedules, 100, idList, dlgID);
};
//Get the linked schedule data
DupliJs.Storage.getScheduleData = function(storageIDs) {
var result = null;
var html;
$.ajax({
type: "POST",
url: ajaxurl,
async: false,
dataType: "json",
data: {
action: 'duplicator_storage_bulk_actions',
perform: <?php echo (int) ServicesStorage::STORAGE_GET_SCHEDULES; ?>,
storage_ids: storageIDs,
nonce: '<?php echo esc_js($storage_bulk_action_nonce); ?>'
}
})
.done(function(data) {
//__sleepFor(1000); //Test delays
if (data.schedules !== undefined && data.schedules.length > 0) {
html = '';
data.schedules.forEach(function(schedule) {
let name = $("<div/>").text(schedule.name).html();
let asterisk = schedule.hasOneStorage ? "*" : "";
html += `<div class="schedule-item">
<i class="far fa-clock"></i> <a href="${schedule.editURL}">${name}</a> <span class="maroon">${asterisk}</span>
</div>`;
});
result = html;
}
})
.fail(function() {
result = '<i class="fas fa-exclamation-triangle"></i> <?php esc_html_e('Unable to get schedule data.', 'duplicator-pro') ?>';
});
return result;
};
//Perform the delete via ajax
DupliJs.Storage.deleteAjax = function() {
var dlgID = "<?php echo esc_js($dlgDelete->getID()); ?>";
var list = DupliJs.Storage.SelectedList();
//Delete from the quick link
if (list.length == 0) {
var singleID = $('#dup-selected-storage').val();
list = (singleID > 0) ? [singleID] : null;
}
$(`#${dlgID}_message`).hide();
$.ajax({
type: "POST",
url: ajaxurl,
dataType: "json",
data: {
action: 'duplicator_storage_bulk_actions',
perform: <?php echo (int) ServicesStorage::STORAGE_BULK_DELETE; ?>,
storage_ids: list,
nonce: '<?php echo esc_js($storage_bulk_action_nonce); ?>'
}
})
.done(function() {
$('#dup-storage-form').submit()
})
.always(function() {
$('#dup-selected-storage').val(null)
});
};
});
//Used to test ajax delays
function __sleepFor(sleepDuration) {
var now = new Date().getTime();
while (new Date().getTime() < now + sleepDuration) {
/* Do nothing */
}
}
</script>

View File

@@ -0,0 +1,167 @@
<?php
/**
* @package Duplicator
*/
defined("ABSPATH") or die("");
use Duplicator\Core\Views\TplMng;
/**
* Variables
*
* @var Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
* @var Duplicator\Models\Storages\AbstractStorageEntity $storage
*/
$storage = $tplData['storage'];
/** @var int */
$index = $tplData['index'];
$typeName = $storage->getStypeName();
$typeId = $storage->getSType();
$invalidErrorMsg = __('Invalid storage configuration', 'duplicator-pro');
$isValid = $storage->isValid($invalidErrorMsg);
$isSupported = $storage::isSupported();
$row_classes = [ 'storage-row' ];
if ($index % 2) {
$row_classes[] = 'alternate';
}
if (!$isSupported) {
$row_classes[] = 'unsupported';
$shortDescWarning = __('Storage Type Not Supported', 'duplicator-pro');
$longDescWarning = __(
'This storage type is not supported on this server. Please remove this storage or contact your host to install the required extensions.',
'duplicator-pro'
);
} elseif (!$isValid) {
$row_classes[] = 'invalid';
$shortDescWarning = $invalidErrorMsg;
$longDescWarning = __(
'This storage has invalid configuration and cannot be used. Please edit and fix the configuration.',
'duplicator-pro'
);
} else {
$shortDescWarning = '';
$longDescWarning = '';
}
?>
<tr id="main-view-<?php echo (int) $storage->getId() ?>"
class="<?php echo esc_attr(implode(' ', $row_classes)); ?>"
data-delete-view="<?php echo esc_attr($storage->getDeleteView(false)); ?>"
>
<td class="storage-checkbox">
<?php if ($storage->isDefault()) : ?>
<input type="checkbox" disabled="disabled" />
<?php else : ?>
<input name="selected_id[]" type="checkbox" value="<?php echo (int) $storage->getId(); ?>" class="item-chk" />
<?php endif; ?>
</td>
<td class="storage-name">
<a href="javascript:void(0);" onclick="DupliJs.Storage.Edit('<?php echo (int) $storage->getId(); ?>')">
<b><?php echo esc_html($storage->getName()); ?></b>
<?php if (!$isSupported || !$isValid) : ?>
&nbsp;<i class="fas fa-exclamation-triangle alert-color" title="<?php echo esc_attr($shortDescWarning); ?>"></i>
<?php endif; ?>
</a>
<div class="sub-menu">
<a href="javascript:void(0);" onclick="DupliJs.Storage.Edit('<?php echo (int) $storage->getId(); ?>')">
<?php esc_html_e('Edit', 'duplicator-pro'); ?>
</a>
|
<a href="javascript:void(0);" onclick="DupliJs.Storage.View('<?php echo (int) $storage->getId(); ?>');">
<?php esc_html_e('Quick View', 'duplicator-pro'); ?>
</a>
<?php if (!$storage->isDefault()) : ?>
<?php if (!$storage->isLocal()) : ?>
|
<a href="javascript:void(0);" onclick="DupliJs.Storage.CopyEdit('<?php echo (int) $storage->getId(); ?>');">
<?php esc_html_e('Copy', 'duplicator-pro'); ?>
</a>
<?php endif; ?>
|
<a href="javascript:void(0);" onclick="DupliJs.Storage.deleteSingle('<?php echo (int) $storage->getId(); ?>');">
<?php esc_html_e('Delete', 'duplicator-pro'); ?>
</a>
<?php endif; ?>
</div>
</td>
<td class="storage-type">
<?php
echo wp_kses(
$storage->getStypeIcon(),
[
'i' => [
'class' => [],
],
'img' => [
'src' => [],
'class' => [],
'alt' => [],
],
]
),
'&nbsp;',
esc_html($storage->getStypeName());
?>
</td>
</tr>
<?php
ob_start();
try { ?>
<tr id='quick-view-<?php echo (int) $storage->getId(); ?>'
class='<?php echo ($index % 2) ? 'alternate' : ''; ?> storage-detail'>
<td colspan="3">
<b><?php esc_html_e('QUICK VIEW', 'duplicator-pro') ?></b> <br/>
<div>
<label><?php esc_html_e('Name', 'duplicator-pro') ?>:</label>
<?php echo esc_html($storage->getName()); ?>
</div>
<div>
<label><?php esc_html_e('Notes', 'duplicator-pro') ?>:</label>
<?php echo (strlen($storage->getNotes())) ? esc_html($storage->getNotes()) : esc_html__('(no notes)', 'duplicator-pro'); ?>
</div>
<div>
<label><?php esc_html_e('Type', 'duplicator-pro') ?>:</label>
<?php echo esc_html($storage->getStypeName()); ?>
</div>
<?php $storage->getListQuickView(); ?>
<?php if (!$isSupported || !$isValid) : ?>
<div class="storage-status-warning">
<p>
<i class="fas fa-exclamation-triangle alert-color"></i>&nbsp;
<strong><?php echo esc_html($shortDescWarning); ?></strong>
</p>
<?php echo esc_html($longDescWarning); ?>
</div>
<?php endif; ?>
<button type="button" class="button secondary hollow tiny"
onclick="DupliJs.Storage.View('<?php echo (int) $storage->getId(); ?>');">
<?php esc_html_e('Close', 'duplicator-pro') ?>
</button>
</td>
</tr>
<?php
} catch (Exception $e) {
ob_clean(); ?>
<tr id='quick-view-<?php echo intval($storage->getId()); ?>' class='<?php echo ($index % 2) ? 'alternate' : ''; ?>'>
<td colspan="3">
<?php TplMng::getInstance()->render(
'admin_pages/storages/parts/storage_error',
['exception' => $e]
); ?>
<br><br>
<button type="button" class="button" onclick="DupliJs.Storage.View('<?php echo intval($storage->getId()); ?>');">
<?php esc_html_e('Close', 'duplicator-pro') ?>
</button>
</td>
</tr>
<?php
}
ob_end_flush();

View File

@@ -0,0 +1,27 @@
<?php
/**
* @package Duplicator
*/
defined("ABSPATH") or die("");
/**
* Admin page packages list
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*
* @var Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var Duplicator\Core\Views\TplMng $tplMng
*/
?>
<tr>
<td colspan="3">
<div class="maroon">
<?php esc_html_e('Error reading storages', 'duplicator-pro'); ?>
</div>
</td>
</tr>

View File

@@ -0,0 +1,152 @@
<?php
/**
* @package Duplicator
*/
defined("ABSPATH") or die("");
use Duplicator\Controllers\SettingsPageController;
use Duplicator\Core\Controllers\ControllersManager;
/**
* Variables
*
* @var Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var Duplicator\Core\Views\TplMng $tplMng
*/
?>
<script>
jQuery(document).ready(function ($) {
// Quick fix for submint/enter error
$(window).on('keyup keydown', function (e) {
if (!$(e.target).is('textarea'))
{
var keycode = (typeof e.keyCode != 'undefined' && e.keyCode > -1 ? e.keyCode : e.which);
if ((keycode === 13)) {
e.preventDefault();
return false;
}
}
});
// Removes the values of hidden input fields marked with class dup-empty-field-on-submit
DupliJs.Storage.EmptyValues = function () {
$(':hidden .dup-empty-field-on-submit').val('');
}
// Removes tags marked with class dup-remove-on-submit-if-hidden, if they are hidden
DupliJs.Storage.RemoveMarkedHiddenTags = function () {
$('.dup-remove-on-submit-if-hidden:hidden').each(function() {
$(this).remove();
});
}
DupliJs.Storage.PrepareForSubmit = function () {
DupliJs.Storage.EmptyValues();
if ($('#dup-storage-form').parsley().isValid()) {
// The form is about to be submitted.
DupliJs.Storage.RemoveMarkedHiddenTags();
}
}
$('#dup-storage-form').submit(DupliJs.Storage.PrepareForSubmit);
DupliJs.Storage.AuthMessages = function () {
let reloadUrl = new URL(window.location.href);
let authMessage = reloadUrl.searchParams.get('dup-auth-message');
let revokeMessage = reloadUrl.searchParams.get('dup-revoke-message');
if (authMessage || revokeMessage) {
// Display messages
if (authMessage) {
DupliJs.addAdminMessage(authMessage, 'notice');
}
if (revokeMessage) {
DupliJs.addAdminMessage(revokeMessage, 'notice');
}
// Remove the params from URL to prevent persistence
reloadUrl.searchParams.delete('dup-auth-message');
reloadUrl.searchParams.delete('dup-revoke-message');
reloadUrl.searchParams.delete('dup-storage-id');
window.history.replaceState({}, '', reloadUrl.href);
}
}
DupliJs.Storage.RevokeAuth = function (storageId)
{
// Get current page slug from URL
const currentPage = new URL(window.location.href).searchParams.get('page') || '';
DupliJs.Util.ajaxWrapper(
{
action: 'duplicator_revoke_storage',
storage_id: storageId,
current_page: currentPage,
nonce: '<?php echo esc_js(wp_create_nonce('duplicator_revoke_storage')); ?>'
},
function (result, data, funcData, textStatus, jqXHR) {
if (funcData.success) {
// Backend provides the complete redirect URL
if (funcData.redirect_url) {
window.location.href = funcData.redirect_url;
} else {
// Fallback: simple reload
window.location.reload();
}
} else {
DupliJs.addAdminMessage(funcData.message, 'error');
}
return '';
}
);
}
DupliJs.Storage.Authorize = function (storageId, storageType, extraData)
{
// Get current page slug from URL
const currentPage = new URL(window.location.href).searchParams.get('page') || '';
extraData.action = 'duplicator_auth_storage';
extraData.storage_id = storageId;
extraData.storage_type = storageType;
extraData.current_page = currentPage;
extraData.nonce = '<?php echo esc_js(wp_create_nonce('duplicator_auth_storage')); ?>';
DupliJs.Util.ajaxWrapper(
extraData,
function (result, data, funcData, textStatus, jqXHR) {
if (funcData.success) {
// Backend provides the complete redirect URL
if (funcData.redirect_url) {
// Set unsaved changes to false, not to trigger alert during finalization
DupliJs.UI.hasUnsavedChanges = false;
window.location.href = funcData.redirect_url;
} else {
// Fallback: simple reload
DupliJs.UI.hasUnsavedChanges = false;
window.location.reload();
}
} else {
DupliJs.addAdminMessage(funcData.message, 'error');
}
return '';
}
);
return false;
}
// Toggles Save Provider button for existing Storages only
DupliJs.UI.formOnChangeValues($('#dup-storage-form'), function() {
$('#button_file_test').prop('disabled', true);
});
//Init
DupliJs.Storage.AuthMessages();
jQuery('#name').focus().select();
});
</script>

View File

@@ -0,0 +1,68 @@
<?php
/**
* @package Duplicator
*/
use Duplicator\Utils\Support\SupportToolkit;
defined("ABSPATH") or die("");
/**
* Admin page packages list
*
* @package Duplicator
* @copyright (c) 2022, Snap Creek LLC
*
* @var Duplicator\Core\Controllers\ControllersManager $ctrlMng
* @var Duplicator\Core\Views\TplMng $tplMng
* @var array<string, mixed> $tplData
*/
$storageInfos = $tplData['storageInfos'] ?? [];
if (count($storageInfos) < 1) {
return;
}
$isAllDownload = $tplData['isAllDownload'] ?? false;
$isAllUpload = $tplData['isAllUpload'] ?? false;
$failureMessage = $tplData['failureMessage'] ?? __('There was a problem transferring the backup(s).', 'duplicator-pro');
?>
<p> <?php echo wp_kses($failureMessage, [ 'b' => [], 'i' => [] ]); ?> </p>
<?php if (count($storageInfos) > 1) { ?>
<ul>
<?php foreach ($storageInfos as $info) { ?>
<li>
<b><?php echo esc_html($info['name']); ?></b> (<?php echo esc_html($info['type']); ?>)
<?php if (!$isAllDownload && !$isAllUpload) { ?>
-
<b class="maroon">
<?php echo $info['isDownload'] ? esc_html__('Download Failed', 'duplicator-pro') : esc_html__('Upload Failed', 'duplicator-pro'); ?>
</b>
<?php } ?>
</li>
<?php } ?>
</ul>
<?php } ?>
<p><?php esc_html_e('Please try transferring again.', 'duplicator-pro'); ?></p>
<p>
<?php echo wp_kses(
sprintf(
esc_html_x(
'If the issue persists, %1$scontact support%2$s with the %3$s attached to the ticket.',
'1: open link tag, 2: close link tag, 3: diagnostic data link with label or link to instructions to download the Backup logs',
'duplicator-pro'
),
'<a href="' . esc_url(DUPLICATOR_BLOG_URL . 'my-account/support/') . '" target="_blank">',
'</a>',
SupportToolkit::getDiagnosticInfoLinks(['package'])
),
[
'a' => [
'href' => [],
'target' => [],
],
]
); ?>
</p>